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}