Skip to main content

Vine/
Host.rs

1//! # Vine::Host
2//!
3//! [`VineHost`] is the embedder-facing seam between Vine and its consumer
4//! runtime. Mountain (Tauri runtime), Air (background daemon), and any
5//! Rust-side Cocoon client implement this trait to expose the minimum
6//! surface Vine's notification handlers need: application-state access,
7//! renderer event emission, and an [`IPCProvider`] handle for cross-channel
8//! re-entrancy. Handlers operate on `&dyn VineHost` so a single handler
9//! tree can be hosted against any embedder runtime.
10//!
11//! ## Design notes
12//!
13//! - [`ApplicationState`](VineHost::ApplicationState) returns `&dyn
14//!   ApplicationStateAccess`. Vine treats application state as opaque;
15//!   embedders decide what their state exposes via embedder-local sub-traits
16//!   and downcasting.
17//! - [`EmitToRenderer`](VineHost::EmitToRenderer) is the single entry point for
18//!   "send a value to the workbench / Sky window." Mountain wires it to
19//!   `tauri::WebviewWindow::emit`; Air leaves it as a no-op (no renderer).
20//! - [`IPCProvider`](VineHost::IPCProvider) returns `Arc<dyn IPCProvider>` for
21//!   handlers that need to re-enter the IPC bus.
22//!
23//! ## Stability
24//!
25//! Adding methods to [`VineHost`] is a compatible change so long as every
26//! impl is updated in the same revision. Removing a method requires
27//! sweeping every consumer.
28
29use std::sync::Arc;
30
31use serde_json::Value;
32
33/// Opaque application-state handle exposed to Vine handlers.
34///
35/// Embedders downcast or call sub-trait methods declared in their own crate.
36/// Vine itself never reaches into the state; handlers do.
37pub trait ApplicationStateAccess: Send + Sync {
38	/// Returns the embedder name (e.g. "Mountain", "Air"). Useful for
39	/// diagnostic logs that fan in from multiple hosts.
40	fn EmbedderName(&self) -> &'static str;
41}
42
43/// Cross-channel IPC provider abstraction.
44///
45/// Mirrors the shape of `CommonLibrary::IPC::IPCProvider` so consumers can
46/// swap between the two with a single `use` change. Kept local to Vine to
47/// avoid pulling `CommonLibrary` into the dependency graph.
48pub trait IPCProvider: Send + Sync {
49	/// Sends a request on the named channel and waits for a JSON response.
50	fn SendRequest(&self, Channel:&str, Payload:Value) -> futures::future::BoxFuture<'_, crate::Error::Result<Value>>;
51
52	/// Fire-and-forget notification on the named channel.
53	/// `Method` is the gRPC method name inside the channel (e.g.
54	/// `"$onDidChangeBreakpoints"`).
55	fn SendNotification(&self, Channel:&str, Method:&str, Payload:Value);
56}
57
58/// Cheap-to-clone renderer event sink.
59///
60/// Handlers with long-lived flushers (the channel-drain coalescers used by
61/// `ProgressReport`, `DecorationTypeLifecycle`, `OutputChannelCoalesce`)
62/// capture an `Arc<dyn RendererEmitter>` once and reuse it across awaits.
63/// Embedders implement this trait on a tiny struct that holds whatever
64/// transport handle is needed (e.g. `tauri::AppHandle`), independent of
65/// the full [`VineHost`] surface.
66pub trait RendererEmitter: Send + Sync + 'static {
67	/// Emits `Payload` on the renderer's `Channel`. Embedders without a
68	/// renderer leave this a no-op.
69	fn Emit(&self, Channel:&str, Payload:Value);
70}
71
72/// The embedder-facing seam between Vine and its host runtime.
73///
74/// Implementations belong in the embedder crate (Mountain, Air, …), not in
75/// Vine.
76pub trait VineHost: Send + Sync {
77	/// Returns the embedder's application state for handler use.
78	fn ApplicationState(&self) -> &dyn ApplicationStateAccess;
79
80	/// Emits a JSON event on the named renderer channel. No-op for embedders
81	/// that have no renderer (e.g. Air).
82	fn EmitToRenderer(&self, Channel:&str, Payload:Value);
83
84	/// Returns a cheap-to-clone renderer event sink. Used by handlers
85	/// with long-lived flushers that need to emit from a background
86	/// task without borrowing the full host.
87	fn RendererEmitter(&self) -> Arc<dyn RendererEmitter>;
88
89	/// Returns the cross-channel IPC provider. Used by handlers that need to
90	/// re-enter the IPC bus (e.g. tree-view registration that needs to call
91	/// `sky:replay-events`).
92	fn IPCProvider(&self) -> Arc<dyn IPCProvider>;
93
94	/// Unregisters a provider by handle. Embedders that maintain a provider
95	/// registry route this to their `ProviderRegistration` table; embedders
96	/// without a registry silently discard.
97	fn UnregisterProvider(&self, Handle:u32);
98
99	/// Inserts a proxied command into the embedder's command dispatch registry.
100	/// `SideCarIdentifier` is the gRPC sidecar to proxy to (e.g.
101	/// `"cocoon-main"`). No-op for embedders without a command registry.
102	fn RegisterCommandInRegistry(&self, CommandId:&str, SideCarIdentifier:&str);
103
104	/// Removes a command from the embedder's dispatch registry.
105	/// No-op for embedders without a command registry.
106	fn UnregisterCommandInRegistry(&self, CommandId:&str);
107
108	// --- Terminal operations ---
109
110	/// Spawns a background task that sends `Text` to the PTY identified by
111	/// `TerminalId`. No-op for embedders without terminal support.
112	fn SpawnSendTextToTerminal(&self, TerminalId:u64, Text:String);
113
114	/// Spawns a background task that disposes the PTY identified by
115	/// `TerminalId`. No-op for embedders without terminal support.
116	fn SpawnDisposeTerminal(&self, TerminalId:u64);
117
118	/// Creates a new PTY terminal with the given options JSON and returns
119	/// `Some({ "id": u64, "pid": u64, "name": string })` on success, `None`
120	/// on failure or for embedders without terminal support.
121	fn CreateTerminal<'a>(&'a self, Options:&'a Value) -> futures::future::BoxFuture<'a, Option<Value>>;
122
123	// --- SCM operations ---
124
125	/// Registers an SCM provider in the embedder's `ProviderRegistration`
126	/// table. Called once per `vscode.scm.createSourceControl(...)`
127	/// invocation.
128	fn RegisterScmInRegistry(&self, Handle:u32, ScmId:&str, Label:&str, ExtId:&str);
129
130	/// Forwards a `CreateSourceControl` call to the embedder's
131	/// `SourceControlManagementProvider`. Errors are logged internally.
132	fn CreateSourceControl<'a>(&'a self, Payload:Value) -> futures::future::BoxFuture<'a, ()>;
133
134	/// Forwards an `UpdateSourceControlGroup` call to the embedder's
135	/// `SourceControlManagementProvider`. Errors are logged internally.
136	fn UpdateSourceControlGroup<'a>(&'a self, ScmHandle:u32, Payload:Value) -> futures::future::BoxFuture<'a, ()>;
137
138	// --- Language-feature provider registration ---
139
140	/// Registers a language-feature provider by normalised type name.
141	/// `TypeName` is the wire method stripped of `register_` prefix and
142	/// optional `_provider` suffix (e.g. `"hover"`, `"completion_item"`).
143	/// Returns `true` if the type was recognised and the registration was
144	/// inserted; `false` for unknown type names (no-op embedders always return
145	/// `false`).
146	fn RegisterLanguageProvider(&self, Handle:u32, TypeName:&str, Payload:&Value) -> bool;
147
148	/// Persists a resource-state snapshot for an SCM group in the embedder's
149	/// SCM marker registry. `ScmHandle` is the provider handle,
150	/// `GroupId` identifies the group within that provider, and
151	/// `ResourceStates` is the raw JSON array of resource state objects.
152	/// No-op for embedders without SCM marker support.
153	fn UpdateScmGroupMarkers(&self, ScmHandle:u32, GroupId:&str, ResourceStates:&Value);
154}