ratatui_wgpu/
lib.rs

1//! # Getting Started
2//! Check out the [examples](https://github.com/Jesterhearts/ratatui-wgpu/tree/main/examples)
3//! for a number of programs using `winit` for both native and web.
4//!
5//! A [`WgpuBackend`] can be constructed using a [`Builder`] and then provided
6//! to a [`Terminal`](ratatui::Terminal). After that, rendering can be done as
7//! normal using the ratatui library. If you need custom shader post-processing,
8//! see the [`PostProcessor`] trait or the
9//! [`DefaultPostProcessor`](shaders::DefaultPostProcessor) implementation for
10//! guidance.
11//!
12//! Here's a short example using winit on native with the default post processor
13//! implementation:
14//! ```
15//! # use std::{
16//! #     num::NonZeroU32,
17//! #     sync::Arc,
18//! # };
19//! #
20//! # use chrono::Local;
21//! # use ratatui::{
22//! #     prelude::*,
23//! #     widgets::*,
24//! # };
25//! # use ratatui_wgpu::{
26//! #     Builder,
27//! #     Font,
28//! #     WgpuBackend,
29//! #     Dimensions,
30//! # };
31//! # use winit::{
32//! #     application::ApplicationHandler,
33//! #     event::WindowEvent,
34//! #     event_loop::EventLoop,
35//! #     window::{
36//! #         Window,
37//! #         WindowAttributes,
38//! #     },
39//! # };
40//! #
41//! pub struct App {
42//!     window: Option<Arc<Window>>,
43//!     backend: Option<Terminal<WgpuBackend<'static, 'static>>>,
44//! }
45//!
46//! impl ApplicationHandler for App {
47//!     fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
48//!         self.window = Some(Arc::new(
49//!             event_loop
50//!                 .create_window(WindowAttributes::default())
51//!                 .unwrap(),
52//!         ));
53//!
54//!         let size = self.window.as_ref().unwrap().inner_size();
55//!
56//!         self.backend = Some(
57//!             Terminal::new(
58//!                 futures_lite::future::block_on(
59//!                     Builder::from_font(
60//!                         Font::new(include_bytes!("backend/fonts/CascadiaMono-Regular.ttf"))
61//!                             .unwrap(),
62//!                     )
63//!                     .with_width_and_height(Dimensions {
64//!                         width: NonZeroU32::new(size.width).unwrap(),
65//!                         height: NonZeroU32::new(size.height).unwrap(),
66//!                     })
67//!                     .build_with_target(self.window.as_ref().unwrap().clone()),
68//!                 )
69//!                 .unwrap(),
70//!             )
71//!             .unwrap(),
72//!         );
73//!
74//!         self.window.as_ref().unwrap().request_redraw();
75//!     }
76//!
77//!     fn window_event(
78//!         &mut self,
79//!         event_loop: &winit::event_loop::ActiveEventLoop,
80//!         _window_id: winit::window::WindowId,
81//!         event: winit::event::WindowEvent,
82//!     ) {
83//!         if let WindowEvent::CloseRequested = event {
84//!             event_loop.exit();
85//!             return;
86//!         }
87//!
88//!         let Some(terminal) = self.backend.as_mut() else {
89//!             return;
90//!         };
91//!
92//!         if let WindowEvent::Resized(size) = event {
93//!             terminal.backend_mut().resize(size.width, size.height);
94//!         }
95//!
96//!         terminal
97//!             .draw(|f| {
98//!                 f.render_widget(
99//!                     Paragraph::new(Line::from("Hello World!")).block(Block::bordered()),
100//!                     f.area(),
101//!                 );
102//!             })
103//!             .unwrap();
104//!
105//!         self.window.as_ref().unwrap().request_redraw();
106//!     }
107//! }
108//! ```
109//!
110//! # Limitations
111//! 1. No cursor rendering.
112//!     - The location of the cursor is tracked, and operations using it should
113//!       behave as expected, but the cursor is not rendered to the screen.
114//! 2. Attempting to render more unique (utf8 character * BOLD|ITALIC)
115//!    characters than can fit in the cache in a single draw call will cause
116//!    incorrect rendering. This is ~3750 characters at the default font size
117//!    with most fonts. If you need more than this, file a bug and I'll do the
118//!    work to make rendering handle an unbounded number of unique characters.
119//!    To put that in perspective, rendering every printable ascii character in
120//!    every combination of styles would take (95 * 4) 380 cache entries or ~10%
121//!    of the cache.
122
123pub(crate) mod backend;
124pub(crate) mod colors;
125pub(crate) mod fonts;
126pub mod shaders;
127pub(crate) mod utils;
128
129pub use ratatui;
130use thiserror::Error;
131pub use wgpu;
132
133#[macro_use]
134extern crate log;
135
136/// Represents the various errors that can occur during operation.
137#[derive(Debug, Error)]
138pub enum Error {
139    /// Backend creation failed because the device request failed.
140    #[error("{0}")]
141    DeviceRequestFailed(wgpu::RequestDeviceError),
142    /// Backend creation failed because creating the surface failed.
143    #[error("{0}")]
144    SurfaceCreationFailed(wgpu::CreateSurfaceError),
145    /// Backend creation failed because wgpu didn't provide an
146    /// [`Adapter`](wgpu::Adapter)
147    #[error("{0}")]
148    AdapterRequestFailed(wgpu::RequestAdapterError),
149    /// Backend creation failed because the default surface configuration
150    /// couldn't be loaded.
151    #[error("Failed to get default Surface configuration from wgpu.")]
152    SurfaceConfigurationRequestFailed,
153}
154
155pub type Result<T> = ::std::result::Result<T, Error>;
156
157#[cfg(feature = "ahash")]
158type RandomState = ahash::RandomState;
159#[cfg(not(feature = "ahash"))]
160type RandomState = std::hash::RandomState;
161
162pub use backend::{
163    builder::Builder,
164    wgpu_backend::WgpuBackend,
165    Dimensions,
166    PostProcessor,
167    RenderSurface,
168    RenderTexture,
169    Viewport,
170};
171pub use fonts::{
172    Font,
173    Fonts,
174};