Skip to main content

html_view/
lib.rs

1//! html_view: A lightweight, cross-platform HTML viewer for Rust.
2//!
3//! This library provides a simple API to display HTML content in a native window,
4//! similar to `matplotlib.pyplot.show()` in Python.
5//!
6//! # Quick Start
7//!
8//! ```no_run
9//! use html_view;
10//!
11//! fn main() -> Result<(), html_view::ViewerError> {
12//!     html_view::show("<h1>Hello, World!</h1>")?;
13//!     Ok(())
14//! }
15//! ```
16//!
17//! # Features
18//!
19//! - Display inline HTML, local files, directories, or remote URLs
20//! - Blocking and non-blocking modes
21//! - Window configuration (size, position, title)
22//! - Security controls for navigation and remote content
23//! - Cross-platform (Windows, macOS, Linux)
24
25mod error;
26mod launcher;
27mod locator;
28mod options;
29mod result;
30
31pub use error::ViewerError;
32pub use locator::{AppLocator, DefaultAppLocator};
33pub use options::{ViewerOptions, ViewerWaitMode};
34pub use result::{ViewerHandle, ViewerResult};
35
36// Re-export commonly used types from shared crate
37pub use html_view_shared::{
38    BehaviourOptions, DialogOptions, EnvironmentOptions, ToolbarOptions, ViewerContent,
39    ViewerExitReason, ViewerExitStatus, WindowOptions, WindowTheme,
40};
41
42use launcher::launch_viewer;
43
44/// Display inline HTML in a new viewer window and block until the window is closed.
45///
46/// This is the simplest way to show HTML content. It uses default window and
47/// behaviour options with secure defaults.
48///
49/// # Security
50///
51/// By default:
52/// - Remote content loading is disabled
53/// - External navigation is blocked
54/// - Developer tools are disabled
55/// - Only the provided HTML is displayed
56///
57/// # Examples
58///
59/// Basic HTML display:
60///
61/// ```no_run
62/// html_view::show("<h1>Hello!</h1>").unwrap();
63/// ```
64///
65/// Display with inline styles:
66///
67/// ```no_run
68/// html_view::show(r#"
69///     <html>
70///     <head>
71///         <style>
72///             body { font-family: Arial; padding: 40px; }
73///             h1 { color: #4A90E2; }
74///         </style>
75///     </head>
76///     <body>
77///         <h1>Styled Content</h1>
78///         <p>This HTML includes CSS styling.</p>
79///     </body>
80///     </html>
81/// "#).unwrap();
82/// ```
83///
84/// Generate HTML dynamically:
85///
86/// ```no_run
87/// let items = vec!["Item 1", "Item 2", "Item 3"];
88/// let html = format!(
89///     "<h1>My List</h1><ul>{}</ul>",
90///     items.iter()
91///         .map(|item| format!("<li>{}</li>", item))
92///         .collect::<String>()
93/// );
94/// html_view::show(html).unwrap();
95/// ```
96///
97/// # Errors
98///
99/// Returns an error if the viewer binary cannot be found or launched, or if
100/// there's an I/O error during the process.
101///
102/// Common error scenarios:
103/// - [`ViewerError::BinaryNotFound`]: The `html_view_app` binary is not installed
104/// - [`ViewerError::SpawnFailed`]: Failed to start the viewer process
105/// - [`ViewerError::VersionMismatch`]: Library and viewer versions are incompatible
106///
107/// # See Also
108///
109/// - [`show_with_options`] for custom window configuration
110/// - [`open`] for more advanced usage with full option control
111pub fn show<S: Into<String>>(html: S) -> Result<(), ViewerError> {
112    let options = ViewerOptions::inline_html(html);
113    match open(options)? {
114        ViewerResult::Blocking(_status) => Ok(()),
115        ViewerResult::NonBlocking(_) => unreachable!("inline_html uses Blocking mode"),
116    }
117}
118
119/// Display HTML with custom window configuration.
120///
121/// This is a convenience function that allows you to customize the window
122/// while using the simple blocking API.
123///
124/// # Examples
125///
126/// Custom window size and title:
127///
128/// ```no_run
129/// use html_view::{show_with_options, WindowOptions};
130///
131/// let mut window = WindowOptions::default();
132/// window.width = Some(800);
133/// window.height = Some(600);
134/// window.title = Some("My Custom Window".to_string());
135///
136/// show_with_options("<h1>Custom Window</h1>", window).unwrap();
137/// ```
138///
139/// Frameless window:
140///
141/// ```no_run
142/// use html_view::{show_with_options, WindowOptions};
143///
144/// let mut window = WindowOptions::default();
145/// window.decorations = false;
146/// window.always_on_top = true;
147///
148/// show_with_options("<h1>Always on Top</h1>", window).unwrap();
149/// ```
150///
151/// # Errors
152///
153/// See [`show`] for error documentation.
154pub fn show_with_options<S: Into<String>>(
155    html: S,
156    window_options: WindowOptions,
157) -> Result<(), ViewerError> {
158    let mut options = ViewerOptions::inline_html(html);
159    options.window = window_options;
160
161    match open(options)? {
162        ViewerResult::Blocking(_status) => Ok(()),
163        ViewerResult::NonBlocking(_) => unreachable!("inline_html uses Blocking mode"),
164    }
165}
166
167/// Open a viewer window with the given options.
168///
169/// This is the most flexible way to use html_view. It provides full control over
170/// all window, behavior, and environment options.
171///
172/// Returns either a blocking result with the exit status or a non-blocking
173/// handle, depending on `options.wait`.
174///
175/// # Examples
176///
177/// Non-blocking mode with handle:
178///
179/// ```no_run
180/// use html_view::{ViewerOptions, ViewerWaitMode, ViewerResult};
181///
182/// let mut options = ViewerOptions::inline_html("<h1>Non-blocking</h1>");
183/// options.wait = ViewerWaitMode::NonBlocking;
184///
185/// match html_view::open(options).unwrap() {
186///     ViewerResult::NonBlocking(mut handle) => {
187///         println!("Viewer started with ID: {}", handle.id);
188///
189///         // Do other work while viewer is open...
190///         std::thread::sleep(std::time::Duration::from_secs(2));
191///
192///         // Wait for it to close
193///         let status = handle.wait().unwrap();
194///         println!("Viewer exited: {:?}", status.reason);
195///     }
196///     _ => unreachable!(),
197/// }
198/// ```
199///
200/// With timeout:
201///
202/// ```no_run
203/// use html_view::ViewerOptions;
204///
205/// let mut options = ViewerOptions::inline_html("<h1>Auto-close</h1>");
206/// options.environment.timeout_seconds = Some(5);
207///
208/// html_view::open(options).unwrap();
209/// // Window closes automatically after 5 seconds
210/// ```
211///
212/// Loading a file with devtools:
213///
214/// ```no_run
215/// use html_view::ViewerOptions;
216/// use std::path::PathBuf;
217///
218/// let mut options = ViewerOptions::local_file(PathBuf::from("index.html"));
219/// options.behaviour.enable_devtools = true;
220/// options.window.width = Some(1200);
221/// options.window.height = Some(800);
222///
223/// html_view::open(options).unwrap();
224/// ```
225///
226/// Remote URL with security settings:
227///
228/// ```no_run
229/// use html_view::ViewerOptions;
230/// use url::Url;
231///
232/// let mut options = ViewerOptions::remote_url(
233///     Url::parse("https://example.com").unwrap()
234/// );
235/// options.behaviour.allow_external_navigation = true;
236/// options.behaviour.allowed_domains = Some(vec![
237///     "example.com".to_string(),
238///     "cdn.example.com".to_string(),
239/// ]);
240///
241/// html_view::open(options).unwrap();
242/// ```
243///
244/// # Errors
245///
246/// Returns an error if the viewer binary cannot be found or launched, or if
247/// there's an I/O error during the process.
248///
249/// See [`ViewerError`] for all possible error types.
250///
251/// # See Also
252///
253/// - [`show`] for the simplest API
254/// - [`ViewerOptions`] for all configuration options
255/// - [`ViewerWaitMode`] for blocking vs non-blocking behavior
256pub fn open(options: ViewerOptions) -> Result<ViewerResult, ViewerError> {
257    launch_viewer(options, &DefaultAppLocator)
258}