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}