Overview
The jarvis-webview crate provides embedded web content for Jarvis panes. It wraps the wry crate (WebKit on macOS, WebView2 on Windows, WebKitGTK on Linux) and provides:
Managed WebView instances per pane
Bidirectional IPC (Rust ↔ JavaScript)
Custom jarvis:// protocol for serving bundled content
Navigation control and security
Event handling (page load, title change, etc.)
Public API
WebViewManager
Manages all WebView instances across tiling panes.
use jarvis_webview :: WebViewManager ;
let manager = WebViewManager :: new ();
Create a new WebView manager.
drain_events
fn(&self) -> Vec<WebViewEvent>
Drain all pending events from all WebViews.
WebViewConfig
Configuration for creating a WebView.
ID of the pane this WebView belongs to.
Initial URL to navigate to.
Initial HTML to load (overrides initial_url).
Whether the WebView background is transparent.
Enable browser DevTools (right-click → Inspect).
WebViewHandle
Handle to a specific WebView instance.
use jarvis_webview :: WebViewHandle ;
// Navigate to a URL
handle . load_url ( "https://docs.rs" );
// Load HTML
handle . load_html ( "<h1>Hello!</h1>" );
// Go back/forward
handle . go_back ();
handle . go_forward ();
// Evaluate JavaScript
handle . eval ( "console.log('Hello from Rust!')" );
WebViewRegistry
Global registry of all WebView instances.
use jarvis_webview :: WebViewRegistry ;
let registry = WebViewRegistry :: new ();
registry . register ( pane_id , handle );
if let Some ( handle ) = registry . get ( pane_id ) {
handle . load_url ( "https://example.com" );
}
IPC System
IPC Messages (JS → Rust)
JavaScript sends messages to Rust via window.jarvis.ipc.postMessage().
Message type / command name.
Text(String) — Simple text payload
Json(serde_json::Value) — Structured JSON
None — No payload
JavaScript API
The IPC_INIT_SCRIPT injects this API into every WebView:
// Send a message to Rust
window . jarvis . ipc . send ( 'command_name' , { foo: 'bar' });
// Register a handler for messages from Rust
window . jarvis . ipc . on ( 'rust_event' , ( payload ) => {
console . log ( 'Received from Rust:' , payload );
});
// Request-response pattern (async)
const result = await window . jarvis . ipc . request ( 'get_data' , {});
console . log ( result );
Built-in IPC Message Types
These messages are automatically handled:
Sent when the WebView is clicked (to focus the pane).
keybind
{ key, ctrl, alt, shift, meta }
Forward keyboard shortcut to Rust.
Request clipboard content (returns { kind, text, data_url }).
Send input to the PTY (for terminal emulator).
Command palette item clicked.
Command palette item hovered.
Command palette dismissed.
Debug event (mousedown, keydown, focus, blur).
IPC Events (Rust → JS)
Rust sends messages to JavaScript via js_dispatch_message().
use jarvis_webview :: ipc :: js_dispatch_message;
use serde_json :: json;
let js = js_dispatch_message (
"config_updated" ,
& json! ({ "theme" : "tokyo-night" })
);
handle . eval ( & js );
In JavaScript:
window . jarvis . ipc . on ( 'config_updated' , ( payload ) => {
console . log ( 'New theme:' , payload . theme );
});
Built-in IPC Events
palette_show
{ items, query, selectedIndex, mode, placeholder }
Show the command palette.
palette_update
{ items, query, selectedIndex, mode, placeholder }
Update command palette state.
Hide the command palette.
WebView Events
Events emitted by WebView instances. Page load state changed. state is PageLoadState::Started or PageLoadState::Finished.
IPC message received from JavaScript. body is raw JSON string — parse with IpcMessage::from_json().
A navigation was requested.
WebView was closed/destroyed.
Started — Navigation has started
Finished — Page has fully loaded (DOMContentLoaded + resources)
Navigation Security
Allowed Navigation Prefixes
use jarvis_webview :: ALLOWED_NAV_PREFIXES ;
for prefix in ALLOWED_NAV_PREFIXES {
println! ( "Allowed: {}" , prefix );
}
Allowed prefixes:
https://
http://localhost
http://127.0.0.1
jarvis://
is_navigation_allowed
use jarvis_webview :: is_navigation_allowed;
assert! ( is_navigation_allowed ( "https://docs.rs" ));
assert! ( is_navigation_allowed ( "http://localhost:3000" ));
assert! ( ! is_navigation_allowed ( "file:///etc/passwd" ));
Custom Protocol
The jarvis:// protocol serves bundled content.
// Load bundled HTML
window . location = 'jarvis://games/wordle.html' ;
// Load bundled image
const img = new Image ();
img . src = 'jarvis://assets/logo.png' ;
ContentProvider
Provides content for the custom protocol.
use jarvis_webview :: ContentProvider ;
let provider = ContentProvider :: new ( assets_dir );
Command Palette Integration
The IPC system includes a full command palette implementation.
Show Palette from Rust
use jarvis_webview :: ipc :: js_dispatch_message;
use serde_json :: json;
let js = js_dispatch_message ( "palette_show" , & json! ({
"items" : [
{ "label" : "New Terminal" , "keybind" : "Cmd+T" , "category" : "Panels" },
{ "label" : "Close Panel" , "keybind" : "Esc Esc" , "category" : "Panels" }
],
"query" : "" ,
"selectedIndex" : 0 ,
"mode" : "command" ,
"placeholder" : null
}));
handle . eval ( & js );
Handle Palette Events
match event {
WebViewEvent :: IpcMessage { pane_id , body } => {
if let Some ( msg ) = IpcMessage :: from_json ( & body ) {
match msg . kind . as_str () {
"palette_click" => {
let index = msg . payload; // Extract index
// Execute command
}
"palette_dismiss" => {
// Hide palette
}
_ => {}
}
}
}
_ => {}
}
Usage Example
use jarvis_webview :: {
WebViewManager , WebViewConfig , WebViewEvent , IpcMessage
};
#[tokio :: main]
async fn main () {
let manager = WebViewManager :: new ();
let config = WebViewConfig {
pane_id : 1 ,
initial_url : Some ( "https://docs.rs" . to_string ()),
initial_html : None ,
transparent : false ,
devtools : true ,
};
let handle = manager . create ( config , & window ) . unwrap ();
loop {
for event in manager . drain_events () {
match event {
WebViewEvent :: PageLoad { pane_id , state , url } => {
println! ( "Pane {} loaded: {}" , pane_id , url );
}
WebViewEvent :: IpcMessage { pane_id , body } => {
if let Some ( msg ) = IpcMessage :: from_json ( & body ) {
println! ( "IPC: {} - {:?}" , msg . kind, msg . payload);
}
}
_ => {}
}
}
}
}