Make a macro for less boilerplate when moving variables (#12182)
Also: - Simplify open listener implementation - Add set_global API to global traits Release Notes: - N/A
This commit is contained in:
parent
8b57d6d4c6
commit
3eb0418bda
5 changed files with 164 additions and 31 deletions
|
@ -49,6 +49,11 @@ pub trait UpdateGlobal {
|
||||||
where
|
where
|
||||||
C: BorrowAppContext,
|
C: BorrowAppContext,
|
||||||
F: FnOnce(&mut Self, &mut C) -> R;
|
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 {
|
impl<T: Global> UpdateGlobal for T {
|
||||||
|
@ -59,4 +64,11 @@ impl<T: Global> UpdateGlobal for T {
|
||||||
{
|
{
|
||||||
cx.update_global(update)
|
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 {
|
pub fn truncate(s: &str, max_chars: usize) -> &str {
|
||||||
match s.char_indices().nth(max_chars) {
|
match s.char_indices().nth(max_chars) {
|
||||||
None => s,
|
None => s,
|
||||||
|
|
|
@ -17,7 +17,9 @@ use env_logger::Builder;
|
||||||
use fs::RealFs;
|
use fs::RealFs;
|
||||||
use futures::{future, StreamExt};
|
use futures::{future, StreamExt};
|
||||||
use git::GitHostingProviderRegistry;
|
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 image_viewer;
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
@ -38,11 +40,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
|
use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
|
||||||
use util::{
|
use util::{maybe, parse_env_output, paths, with_clone, ResultExt, TryFutureExt};
|
||||||
maybe, parse_env_output,
|
|
||||||
paths::{self},
|
|
||||||
ResultExt, TryFutureExt,
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use welcome::{show_welcome_view, BaseKeymap, FIRST_OPEN};
|
use welcome::{show_welcome_view, BaseKeymap, FIRST_OPEN};
|
||||||
use workspace::{AppState, WorkspaceSettings, WorkspaceStore};
|
use workspace::{AppState, WorkspaceSettings, WorkspaceStore};
|
||||||
|
@ -260,13 +258,11 @@ fn main() {
|
||||||
let session_id = Uuid::new_v4().to_string();
|
let session_id = Uuid::new_v4().to_string();
|
||||||
reliability::init_panic_hook(&app, installation_id.clone(), session_id.clone());
|
reliability::init_panic_hook(&app, installation_id.clone(), session_id.clone());
|
||||||
|
|
||||||
let (listener, mut open_rx) = OpenListener::new();
|
let (open_listener, mut open_rx) = OpenListener::new();
|
||||||
let listener = Arc::new(listener);
|
|
||||||
let open_listener = listener.clone();
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[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");
|
println!("zed is already running");
|
||||||
return;
|
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| {
|
app.on_reopen(move |cx| {
|
||||||
if let Some(app_state) = AppState::try_global(cx).and_then(|app_state| app_state.upgrade())
|
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);
|
GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
|
||||||
git_hosting_providers::init(cx);
|
git_hosting_providers::init(cx);
|
||||||
|
|
||||||
OpenListener::set_global(listener.clone(), cx);
|
OpenListener::set_global(cx, open_listener.clone());
|
||||||
|
|
||||||
settings::init(cx);
|
settings::init(cx);
|
||||||
handle_settings_file_changes(user_settings_file_rx, cx);
|
handle_settings_file_changes(user_settings_file_rx, cx);
|
||||||
|
@ -396,7 +392,7 @@ fn main() {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !urls.is_empty() {
|
if !urls.is_empty() {
|
||||||
listener.open_urls(urls)
|
open_listener.open_urls(urls)
|
||||||
}
|
}
|
||||||
|
|
||||||
match open_rx
|
match open_rx
|
||||||
|
|
|
@ -11,7 +11,7 @@ use collections::VecDeque;
|
||||||
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
|
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel,
|
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::*;
|
pub use open_listener::*;
|
||||||
|
|
||||||
|
|
|
@ -90,30 +90,19 @@ impl OpenRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpenListener {
|
#[derive(Clone)]
|
||||||
tx: UnboundedSender<Vec<String>>,
|
pub struct OpenListener(UnboundedSender<Vec<String>>);
|
||||||
}
|
|
||||||
|
|
||||||
struct GlobalOpenListener(Arc<OpenListener>);
|
impl Global for OpenListener {}
|
||||||
|
|
||||||
impl Global for GlobalOpenListener {}
|
|
||||||
|
|
||||||
impl 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>>) {
|
pub fn new() -> (Self, UnboundedReceiver<Vec<String>>) {
|
||||||
let (tx, rx) = mpsc::unbounded();
|
let (tx, rx) = mpsc::unbounded();
|
||||||
(OpenListener { tx }, rx)
|
(OpenListener(tx), rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_urls(&self, urls: Vec<String>) {
|
pub fn open_urls(&self, urls: Vec<String>) {
|
||||||
self.tx
|
self.0
|
||||||
.unbounded_send(urls)
|
.unbounded_send(urls)
|
||||||
.map_err(|_| anyhow!("no listener for open requests"))
|
.map_err(|_| anyhow!("no listener for open requests"))
|
||||||
.log_err();
|
.log_err();
|
||||||
|
@ -121,7 +110,7 @@ impl OpenListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[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 release_channel::RELEASE_CHANNEL_NAME;
|
||||||
use std::os::{linux::net::SocketAddrExt, unix::net::SocketAddr, unix::net::UnixDatagram};
|
use std::os::{linux::net::SocketAddrExt, unix::net::SocketAddr, unix::net::UnixDatagram};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue