revue/lib.rs
1//! # Revue
2//!
3//! A Vue-style TUI framework for Rust with CSS styling, reactive state management,
4//! and a rich set of widgets for building beautiful terminal user interfaces.
5//!
6//! ## Features
7//!
8//! | Feature | Description |
9//! |---------|-------------|
10//! | **CSS Styling** | External CSS files with variables, selectors, transitions, and hot reload |
11//! | **Flexbox Layout** | Powered by [taffy](https://github.com/DioxusLabs/taffy) for flexible layouts |
12//! | **Reactive State** | Vue-inspired Signal/Computed/Effect pattern |
13//! | **80+ Widgets** | Text, Button, Input, Table, Tree, Modal, Toast, Charts, and more |
14//! | **Markdown & Images** | Built-in markdown rendering with Kitty image protocol support |
15//! | **Developer Tools** | Hot reload, widget inspector, snapshot testing (Pilot) |
16//! | **Theming** | Built-in themes: Dracula, Nord, Monokai, Gruvbox, Catppuccin |
17//!
18//! ## Quick Start
19//!
20//! ```rust,ignore
21//! use revue::prelude::*;
22//!
23//! fn main() -> Result<()> {
24//! let mut app = App::builder().build();
25//! let counter = Counter::new();
26//!
27//! app.run_with_handler(counter, |key, state| {
28//! state.handle_key(&key.key)
29//! })
30//! }
31//!
32//! struct Counter { value: i32 }
33//!
34//! impl Counter {
35//! fn new() -> Self { Self { value: 0 } }
36//!
37//! fn handle_key(&mut self, key: &Key) -> bool {
38//! match key {
39//! Key::Up => { self.value += 1; true }
40//! Key::Down => { self.value -= 1; true }
41//! _ => false,
42//! }
43//! }
44//! }
45//!
46//! impl View for Counter {
47//! fn render(&self, ctx: &mut RenderContext) {
48//! vstack()
49//! .child(Text::new(format!("Count: {}", self.value)))
50//! .child(Text::muted("[↑/↓] to change, [q] to quit"))
51//! .render(ctx);
52//! }
53//! }
54//! ```
55//!
56//! ## CSS Styling
57//!
58//! Revue supports CSS for styling widgets:
59//!
60//! ```css
61//! /* styles.css */
62//! :root {
63//! --primary: #bd93f9;
64//! --bg: #282a36;
65//! }
66//!
67//! .button {
68//! background: var(--primary);
69//! color: var(--bg);
70//! transition: background 0.3s ease;
71//! }
72//!
73//! .button:hover {
74//! background: #ff79c6;
75//! }
76//! ```
77//!
78//! ## Reactive State
79//!
80//! ```rust,ignore
81//! use revue::prelude::*;
82//!
83//! let count = signal(0);
84//! let doubled = computed(move || count.get() * 2);
85//!
86//! effect(move || {
87//! println!("Count changed to: {}", count.get());
88//! });
89//!
90//! count.set(5); // Triggers effect, doubled is now 10
91//! ```
92//!
93//! ## Widget Gallery
94//!
95//! ### Layout
96//! - [`widget::vstack()`] / [`widget::hstack()`] - Vertical/horizontal stack layout
97//! - [`widget::Border`] - Bordered container with title support
98//! - [`widget::Tabs`] - Tab navigation
99//! - [`widget::ScrollView`] - Scrollable content area
100//! - [`widget::Layers`] - Overlapping widgets (for modals, toasts)
101//!
102//! ### Input
103//! - [`widget::Input`] - Single-line text input
104//! - [`widget::TextArea`] - Multi-line text editor
105//! - [`widget::Button`] - Clickable button with variants
106//! - [`widget::Checkbox`] - Toggle checkbox
107//! - [`widget::RadioGroup`] - Radio button group
108//! - [`widget::Select`] - Dropdown selection
109//!
110//! ### Display
111//! - [`widget::Text`] - Styled text display
112//! - [`widget::Markdown`] - Markdown rendering with syntax highlighting
113//! - [`widget::Image`] - Terminal images (Kitty protocol)
114//! - [`widget::Progress`] - Progress bar
115//! - [`widget::Spinner`] - Loading spinner
116//! - [`widget::Badge`] / [`widget::Tag`] - Labels and tags
117//! - [`widget::Avatar`] - User avatar display
118//! - [`widget::Skeleton`] - Loading placeholder
119//!
120//! ### Data
121//! - [`widget::Table`] - Data table with columns
122//! - [`widget::List`] - Selectable list
123//! - [`widget::Tree`] - Hierarchical tree view
124//! - [`widget::Sparkline`] - Inline mini chart
125//! - [`widget::BarChart`] - Bar chart visualization
126//! - [`widget::Canvas`] / [`widget::BrailleCanvas`] - Custom drawing
127//!
128//! ### Feedback
129//! - [`widget::Modal`] - Dialog overlay
130//! - [`widget::Toast`] - Notification popup
131//! - [`widget::CommandPalette`] - Fuzzy command search (Ctrl+P)
132//!
133//! ## Module Overview
134//!
135//! | Module | Description |
136//! |--------|-------------|
137//! | [`app`] | Application lifecycle and event loop |
138//! | [`dom`] | Virtual DOM and rendering tree |
139//! | [`event`] | Keyboard/mouse events and keymaps |
140//! | [`layout`] | Flexbox layout engine |
141//! | [`reactive`] | Signal/Computed/Effect primitives |
142//! | [`render`] | Terminal rendering and buffer |
143//! | [`style`] | CSS parsing and theming |
144//! | [`testing`] | Pilot testing framework |
145//! | [`widget`] | All widget implementations |
146//! | [`worker`] | Background task execution |
147//!
148//! ## Testing with Pilot
149//!
150//! ```rust,ignore
151//! use revue::testing::{Pilot, TestApp};
152//!
153//! #[test]
154//! fn test_counter() {
155//! let mut app = TestApp::new(Counter::new());
156//! let mut pilot = Pilot::new(&mut app);
157//!
158//! pilot
159//! .press(Key::Up)
160//! .press(Key::Up)
161//! .assert_contains("2");
162//! }
163//! ```
164//!
165//! ## Themes
166//!
167//! Built-in themes available via [`style::themes`]:
168//!
169//! - **Dracula** - Dark purple theme
170//! - **Nord** - Arctic blue theme
171//! - **Monokai** - Classic dark theme
172//! - **Gruvbox** - Retro groove theme
173//! - **Catppuccin** - Pastel dark theme
174//!
175//! ## Comparison with Other Frameworks
176//!
177//! | Feature | Revue | Ratatui | Textual | Cursive |
178//! |---------|-------|---------|---------|---------|
179//! | Language | Rust | Rust | Python | Rust |
180//! | CSS Styling | ✅ | ❌ | ✅ | ❌ |
181//! | Reactive State | ✅ | ❌ | ✅ | ❌ |
182//! | Hot Reload | ✅ | ❌ | ✅ | ❌ |
183//! | Widget Count | 80+ | 13 | 35+ | 40+ |
184//! | Snapshot Testing | ✅ | ❌ | ❌ | ❌ |
185
186#![warn(missing_docs)]
187
188// Internal logging macros - no-op when tracing feature is disabled
189#[cfg(feature = "tracing")]
190macro_rules! log_debug {
191 ($($arg:tt)*) => { tracing::debug!($($arg)*) }
192}
193#[cfg(not(feature = "tracing"))]
194macro_rules! log_debug {
195 ($($arg:tt)*) => { { let _ = ($($arg)*,); } }
196}
197pub(crate) use log_debug;
198
199#[cfg(feature = "tracing")]
200macro_rules! log_warn {
201 ($($arg:tt)*) => { tracing::warn!($($arg)*) }
202}
203#[cfg(not(feature = "tracing"))]
204macro_rules! log_warn {
205 ($($arg:tt)*) => { { let _ = ($($arg)*,); } }
206}
207pub(crate) use log_warn;
208
209#[cfg(feature = "tracing")]
210macro_rules! log_error {
211 ($($arg:tt)*) => { tracing::error!($($arg)*) }
212}
213#[cfg(not(feature = "tracing"))]
214macro_rules! log_error {
215 ($($arg:tt)*) => { { let _ = ($($arg)*,); } }
216}
217pub(crate) use log_error;
218
219pub mod app;
220pub mod constants;
221pub mod devtools;
222pub mod dom;
223pub mod event;
224pub mod layout;
225pub mod patterns;
226pub mod plugin;
227pub mod query;
228pub mod reactive;
229pub mod render;
230pub mod style;
231pub mod tasks;
232pub mod testing;
233pub mod text;
234pub mod utils;
235pub mod widget;
236pub mod worker;
237
238/// Error type for Revue operations.
239///
240/// This enum covers all error cases that can occur when using Revue,
241/// including CSS parsing errors, I/O errors, and general runtime errors.
242///
243/// # Example
244///
245/// ```rust,ignore
246/// use revue::{Error, Result};
247///
248/// fn load_styles() -> Result<()> {
249/// // Operations that might fail...
250/// Ok(())
251/// }
252/// ```
253#[derive(Debug, thiserror::Error)]
254pub enum Error {
255 /// CSS parsing error.
256 ///
257 /// Occurs when parsing invalid CSS syntax or unsupported properties.
258 #[error("CSS error: {0}")]
259 Css(#[from] style::ParseError),
260
261 /// I/O error.
262 ///
263 /// Occurs during file operations (loading CSS, images, etc.).
264 #[error("I/O error: {0}")]
265 Io(#[from] std::io::Error),
266
267 /// Generic error with custom message.
268 ///
269 /// Used for errors that don't fit other categories.
270 #[error("{0}")]
271 Other(String),
272}
273
274/// Result type alias for Revue operations.
275///
276/// Shorthand for `std::result::Result<T, revue::Error>`.
277pub type Result<T> = std::result::Result<T, Error>;
278
279/// Prelude module for convenient imports.
280///
281/// Import everything you need with a single line:
282///
283/// ```rust,ignore
284/// use revue::prelude::*;
285/// ```
286///
287/// # Included Items
288///
289/// ## Core Types
290/// - [`app::App`] - Application builder and runner
291/// - [`widget::View`], [`widget::RenderContext`] - Widget rendering trait
292/// - [`Result`] - Error handling
293///
294/// ## Events
295/// - [`event::Key`], [`event::KeyEvent`], [`event::Event`] - Input handling
296///
297/// ## Reactive
298/// - [`reactive::signal`], [`reactive::computed`], [`reactive::effect`] - State primitives
299/// - [`reactive::Signal`], [`reactive::Computed`] - Reactive types
300///
301/// ## Layout
302/// - [`widget::vstack`], [`widget::hstack`] - Stack layouts
303/// - [`layout::Rect`] - Rectangle geometry
304///
305/// ## Widgets
306/// All 80+ widgets and their constructors are included.
307/// See [`widget`] module documentation for the full list.
308///
309/// ## Testing
310/// - [`testing::Pilot`], [`testing::TestApp`], [`testing::TestConfig`] - Testing utilities
311///
312/// ## Workers
313/// - [`worker::WorkerPool`], [`worker::WorkerHandle`] - Background tasks
314pub mod prelude {
315 // App
316 pub use crate::app::App;
317
318 // Events
319 pub use crate::event::{Event, Key, KeyEvent, MouseButton, MouseEvent, MouseEventKind};
320
321 // Layout
322 pub use crate::layout::Rect;
323
324 // Reactive primitives
325 pub use crate::reactive::{computed, effect, signal, Computed, Signal};
326
327 // Async support
328 pub use crate::reactive::{
329 use_async, use_async_immediate, use_async_poll, AsyncResult, AsyncState,
330 };
331
332 // Style
333 pub use crate::style::Color;
334
335 // Theme system
336 pub use crate::style::{
337 cycle_theme, register_theme, set_theme, set_theme_by_id, theme_ids, toggle_theme,
338 use_theme, Theme, ThemeVariant, Themes,
339 };
340
341 // Animation system
342 pub use crate::style::{
343 easing,
344 effective_duration,
345 // Reduced motion support
346 should_skip_animation,
347 // Widget animation presets
348 widget_animations,
349 Animation,
350 AnimationDirection,
351 AnimationFillMode,
352 AnimationGroup,
353 // Core animation types
354 AnimationState,
355 Animations,
356 Choreographer,
357 CssKeyframe,
358 GroupMode,
359 // CSS @keyframes style
360 KeyframeAnimation,
361 // Choreography
362 Stagger,
363 Tween,
364 };
365
366 // Widgets - Types
367 pub use crate::widget::{
368 Alignment,
369 Anchor,
370 Avatar,
371 AvatarShape,
372 AvatarSize,
373 Badge,
374 BadgeShape,
375 BadgeVariant,
376 BarChart,
377 BarOrientation,
378 Border,
379 BorderType,
380 // Braille canvas
381 BrailleCanvas,
382 BrailleContext,
383 BrailleGrid,
384 // New widgets
385 Button,
386 ButtonVariant,
387 Canvas,
388 Checkbox,
389 CheckboxStyle,
390 Circle,
391 Column,
392 Command,
393 // Command palette
394 CommandPalette,
395 Direction,
396 // Convenience widgets
397 Divider,
398 DividerStyle,
399 DrawContext,
400 EventResult,
401 FilledCircle,
402 FilledRectangle,
403 FocusStyle,
404 Input,
405 Interactive,
406 // Layer system
407 Layers,
408 Line,
409 List,
410 Modal,
411 ModalButton,
412 ModalButtonStyle,
413 Orientation,
414 Pagination,
415 PaginationStyle,
416 Points,
417 Positioned,
418 Progress,
419 ProgressStyle,
420 RadioGroup,
421 RadioLayout,
422 RadioStyle,
423 Rectangle,
424 RenderContext,
425 ScrollView,
426 Select,
427 Shape,
428 Skeleton,
429 SkeletonShape,
430 Sparkline,
431 SparklineStyle,
432 Spinner,
433 SpinnerStyle,
434 Stack,
435 Tab,
436 Table,
437 Tabs,
438 Tag,
439 TagStyle,
440 Text,
441 TextArea,
442 ThemePicker,
443 Timeout,
444 // UX widgets
445 Toast,
446 ToastLevel,
447 ToastPosition,
448 Tree,
449 TreeNode,
450 View,
451 WidgetState,
452 };
453
454 // Feature-gated widget types
455 #[cfg(feature = "image")]
456 pub use crate::widget::{Image, ScaleMode};
457 #[cfg(feature = "markdown")]
458 pub use crate::widget::{Markdown, MarkdownPresentation, ViewMode};
459
460 // Widgets - Constructors
461 pub use crate::widget::{
462 avatar,
463 avatar_icon,
464 badge,
465 barchart,
466 border,
467 braille_canvas,
468 // New constructors
469 button,
470 canvas,
471 checkbox,
472 chip,
473 column,
474 // Command palette
475 command_palette,
476 // Convenience widget constructors
477 divider,
478 dot_badge,
479 hstack,
480 input,
481 // Layer system constructors
482 layers,
483 list,
484 modal,
485 pagination,
486 positioned,
487 progress,
488 radio_group,
489 scroll_view,
490 select,
491 skeleton,
492 skeleton_avatar,
493 skeleton_paragraph,
494 skeleton_text,
495 sparkline,
496 spinner,
497 table,
498 tabs,
499 tag,
500 text,
501 textarea,
502 theme_picker,
503 // UX constructors
504 toast,
505 tree,
506 tree_node,
507 vdivider,
508 vstack,
509 };
510
511 // Feature-gated widget constructors
512 #[cfg(feature = "image")]
513 pub use crate::widget::image_from_file;
514 #[cfg(feature = "markdown")]
515 pub use crate::widget::{markdown, markdown_presentation};
516
517 // DOM system
518 pub use crate::dom::{DomId, DomNode, DomRenderer, DomTree, NodeState, Query, WidgetMeta};
519
520 // Worker system
521 pub use crate::worker::{
522 run_blocking, spawn as spawn_worker, WorkerChannel, WorkerHandle, WorkerMessage,
523 WorkerPool, WorkerState,
524 };
525
526 // Tasks - Timer, TaskRunner, EventBus
527 pub use crate::tasks::{
528 EventBus, EventId, Subscription, TaskId, TaskResult, TaskRunner, Timer, TimerEntry, TimerId,
529 };
530
531 // Patterns - Common TUI patterns
532 pub use crate::patterns::{
533 build_color,
534 priority_color,
535 spinner_char,
536 status_color,
537 // Async operations
538 AsyncTask,
539 BreadcrumbItem,
540 ConfirmAction,
541 ConfirmState,
542 FieldType,
543 FormField,
544 // Form validation
545 FormState,
546 // State management
547 MessageState,
548 NavigationEvent,
549 // Navigation
550 NavigationState,
551 Route,
552 SearchMode,
553 // Search/filter
554 SearchState,
555 ValidationError,
556 Validators,
557 BG,
558 BG_INSET,
559 BG_SUBTLE,
560 BLUE,
561 BORDER,
562 BORDER_MUTED,
563 // Colors
564 CYAN,
565 ERROR,
566 FG,
567 FG_DIM,
568 FG_SUBTLE,
569 GREEN,
570 INFO,
571 ORANGE,
572 PURPLE,
573 RED,
574 SPINNER_FRAMES,
575 SUCCESS,
576 WARNING,
577 YELLOW,
578 };
579
580 // Config loading (requires config feature)
581 #[cfg(feature = "config")]
582 pub use crate::patterns::{AppConfig, ConfigError};
583
584 // Accessibility
585 pub use crate::utils::{
586 // Announcement functions
587 announce,
588 // Widget-specific announcement helpers
589 announce_button_clicked,
590 announce_checkbox_changed,
591 announce_dialog_closed,
592 announce_dialog_opened,
593 announce_error,
594 announce_list_selection,
595 announce_now,
596 announce_success,
597 announce_tab_changed,
598 has_announcements,
599 is_high_contrast,
600 // Preference getters/setters
601 prefers_reduced_motion,
602 set_high_contrast,
603 set_reduced_motion,
604 take_announcements,
605 };
606
607 // Testing (Pilot)
608 pub use crate::testing::{Pilot, TestApp, TestConfig};
609 // Visual regression testing
610 pub use crate::testing::{
611 CapturedCell, CiEnvironment, CiProvider, TestReport, VisualCapture, VisualDiff, VisualTest,
612 VisualTestConfig, VisualTestResult,
613 };
614
615 // DevTools
616 #[allow(deprecated)] // Re-exporting deprecated functions for backwards compatibility
617 pub use crate::devtools::{
618 disable_devtools, enable_devtools, is_devtools_enabled, toggle_devtools, ComputedProperty,
619 DevTools, DevToolsConfig, DevToolsPosition, DevToolsTab, EventFilter, EventLogger,
620 EventType, Inspector, InspectorConfig, LoggedEvent, PropertySource, StateDebugger,
621 StateEntry, StateValue, StyleCategory, StyleInspector, WidgetNode,
622 };
623
624 // Profiler
625 pub use crate::utils::profiler::{
626 profile, profiler_report, start_profile, FlameNode, ProfileGuard, Profiler, Stats, Timing,
627 };
628
629 // Result type
630 pub use crate::Result;
631
632 // Constants
633 pub use crate::constants::{
634 // Animation durations
635 ANIMATION_DEFAULT_DURATION,
636 ANIMATION_FAST_DURATION,
637 ANIMATION_SLOW_DURATION,
638 ANIMATION_VERY_SLOW_DURATION,
639 // Debounce
640 DEBOUNCE_DEFAULT,
641 DEBOUNCE_FILE_SYSTEM,
642 DEBOUNCE_SEARCH,
643 FRAME_DURATION_30FPS,
644 // Frame rates
645 FRAME_DURATION_60FPS,
646 // Messages
647 MESSAGE_DEFAULT_DURATION,
648 MESSAGE_LONG_DURATION,
649 MESSAGE_QUICK_DURATION,
650 POLL_IMMEDIATE,
651 // Screen transitions
652 SCREEN_TRANSITION_DURATION,
653 // Stagger
654 STAGGER_DELAY_DEFAULT,
655 // Tick rates
656 TICK_RATE_DEFAULT,
657 };
658}