Skip to main content

purview_gpui/
ext.rs

1//! [`PurviewAppExt`]: reach the installed [`AppHandle`] from any gpui context.
2
3use std::net::SocketAddr;
4
5use gpui::App;
6use purview::AppHandle;
7
8use crate::install::Installed;
9
10/// Extension on gpui's [`App`] (and thus any `Context<V>`, which derefs to it)
11/// to reach the bridge's [`AppHandle`] — e.g. `cx.purview().open("Detail")` to
12/// open another projected window from inside a view or handler.
13pub trait PurviewAppExt {
14    /// The installed bridge's [`AppHandle`].
15    ///
16    /// # Panics
17    ///
18    /// Panics if no bridge was installed on this `App` (see
19    /// [`Bridge`](crate::Bridge)).
20    fn purview(&self) -> AppHandle<App>;
21
22    /// The installed bridge's [`AppHandle`], or `None` if none was installed.
23    fn try_purview(&self) -> Option<AppHandle<App>>;
24
25    /// The address the MCP server is listening on — the port the OS picked,
26    /// when the requested one was `0`.
27    ///
28    /// `None` if no bridge was installed, or if it serves over stdio (which has
29    /// no address). Use it to reach the address from a view or a handler, long
30    /// after setup — to render it, or to put "copy the connect command" behind
31    /// a button.
32    ///
33    /// The `Option` is honest here in a way it would not be at the setup site:
34    /// an `App` may carry either transport, so this caller genuinely cannot
35    /// know. Where the transport *is* known the address comes without one,
36    /// from [`BoundBridge::local_addr`](crate::BoundBridge::local_addr).
37    fn purview_addr(&self) -> Option<SocketAddr>;
38}
39
40impl PurviewAppExt for App {
41    fn purview(&self) -> AppHandle<App> {
42        self.global::<Installed>().app.clone()
43    }
44
45    fn try_purview(&self) -> Option<AppHandle<App>> {
46        self.try_global::<Installed>().map(|i| i.app.clone())
47    }
48
49    fn purview_addr(&self) -> Option<SocketAddr> {
50        self.try_global::<Installed>().and_then(|i| i.addr)
51    }
52}