### Running Tears Examples with Cargo Source: https://github.com/akiomik/tears/blob/main/README.md Command-line instructions to run various examples provided by the Tears project using Cargo. This includes examples for counter, views, signals, websocket, and http_todo. ```bash cargo run --example counter cargo run --example views cargo run --example signals cargo run --example websocket --features ws,rustls cargo run --example http_todo --features http ``` -------------------------------- ### Complete Tears Counter Example (Rust) Source: https://github.com/akiomik/tears/blob/main/README.md A full example of a Tears application demonstrating a counter that increments every second. It includes message handling for timer ticks and keyboard input ('q' to quit), UI rendering using Ratatui, and setting up subscriptions for timer and terminal events. ```rust use color_eyre::eyre::Result; use crossterm::event::{Event, KeyCode}; use ratatui::{Frame, text::Text}; use tears::prelude::*; use tears::subscription::{terminal::TerminalEvents, time::{Message as TimerMessage, Timer}}; #[derive(Debug, Clone)] enum Message { Tick, Input(Event), InputError(String), } struct Counter { count: u32, } impl Application for Counter { type Message = Message; type Flags = (); fn new(_flags: ()) -> (Self, Command) { (Counter { count: 0 }, Command::none()) } fn update(&mut self, msg: Message) -> Command { match msg { Message::Tick => { self.count += 1; Command::none() } Message::Input(Event::Key(key)) if key.code == KeyCode::Char('q') => { Command::effect(Action::Quit) } Message::InputError(e) => { eprintln!("Input error: {e}"); Command::effect(Action::Quit) } _ => Command::none(), } } fn view(&self, frame: &mut Frame) { let text = Text::raw(format!("Count: {} (Press 'q' to quit)", self.count)); frame.render_widget(text, frame.area()); } fn subscriptions(&self) -> Vec> { vec![ Subscription::new(Timer::new(1000)).map(|timer_msg| { match timer_msg { TimerMessage::Tick => Message::Tick, } }), Subscription::new(TerminalEvents::new()).map(|result| match result { Ok(event) => Message::Input(event), Err(e) => Message::InputError(e.to_string()), }), ] } } #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; // Setup terminal let mut terminal = ratatui::init(); // Run application at 60 FPS let runtime = Runtime::::new((), 60); let result = runtime.run(&mut terminal).await; // Restore terminal ratatui::restore(); result } ``` -------------------------------- ### Tears Application Runtime Execution (Rust) Source: https://github.com/akiomik/tears/blob/main/README.md Shows how to initialize and run a Tears application using the `Runtime`. This snippet assumes the terminal setup is handled elsewhere and focuses on the `run` method call within an async context. ```rust #[tokio::main] async fn main() -> Result<()> { let runtime = Runtime::::new((), 60); // Setup terminal (see complete example below) // ... runtime.run(&mut terminal).await?; Ok(()) } ``` -------------------------------- ### Initialize Tears Runtime Source: https://context7.com/akiomik/tears/llms.txt Demonstrates how to initialize the Runtime with specific flags and a target frame rate to manage the application lifecycle and event loop. ```rust use tears::prelude::*; use ratatui::Frame; struct MyApp; enum Message { Quit } impl Application for MyApp { type Message = Message; type Flags = String; fn new(config: String) -> (Self, Command) { println!("Initialized with config: {}", config); (MyApp, Command::none()) } fn update(&mut self, msg: Message) -> Command { match msg { Message::Quit => Command::effect(Action::Quit), } } fn view(&self, _frame: &mut Frame) {} fn subscriptions(&self) -> Vec> { vec![] } } #[tokio::main] async fn main() -> color_eyre::Result<()> { let mut terminal = ratatui::init(); // Create runtime with flags and 60 FPS target let runtime = Runtime::::new("my-config".to_string(), 60); runtime.run(&mut terminal).await?; ratatui::restore(); Ok(()) } ``` -------------------------------- ### Implement HTTP Query Subscription in Rust Source: https://context7.com/akiomik/tears/llms.txt Shows how to use the Query subscription for automatic data fetching with caching. It covers cache configuration, invalidation, and state management for asynchronous data. ```rust // Enable with: tears = { version = "0.8", features = ["http"] } use std::sync::Arc; use tears::prelude::*; use tears::subscription::http::{Query, QueryClient, QueryState, QueryError, QueryConfig}; use std::time::Duration; #[derive(Debug, Clone)] struct User { id: u32, name: String, } enum Message { UserQuery(tears::subscription::http::QueryResult), RefreshUser, } struct App { query_client: Arc, user_state: QueryState, } impl Default for App { fn default() -> Self { let config = QueryConfig::new( Duration::from_secs(30), Duration::from_secs(300), ); Self { query_client: Arc::new(QueryClient::with_config(config)), user_state: QueryState::Loading, } } } fn update(app: &mut App, msg: Message) -> Command { match msg { Message::UserQuery(result) => { app.user_state = result.state; Command::none() } Message::RefreshUser => { app.query_client.invalidate(&"user-123") } } } fn subscriptions(app: &App) -> Vec> { vec![ Subscription::new(Query::new( &"user-123", || Box::pin(async { Ok::(User { id: 123, name: "John".into() }) }), app.query_client.clone(), )) .map(Message::UserQuery), ] } ``` -------------------------------- ### Implement WebSocket Subscription in Rust Source: https://context7.com/akiomik/tears/llms.txt Demonstrates how to establish a bidirectional WebSocket connection using the Tears library. It includes handling connection status, receiving messages, and sending commands via a mpsc channel. ```rust // Enable with: tears = { version = "0.8", features = ["ws", "rustls"] } use tears::prelude::*; use tears::subscription::websocket::{WebSocket, WebSocketMessage, WebSocketCommand}; use tokio::sync::mpsc; use tokio_tungstenite::tungstenite::Message; enum Msg { WsConnected(mpsc::UnboundedSender), WsDisconnected, WsReceived(String), WsError(String), } struct ChatApp { ws_sender: Option>, messages: Vec, } impl ChatApp { fn send_message(&self, text: String) { if let Some(sender) = &self.ws_sender { let _ = sender.send(WebSocketCommand::SendText(text)); } } fn close_connection(&self) { if let Some(sender) = &self.ws_sender { let _ = sender.send(WebSocketCommand::Close(None)); } } } fn update(app: &mut ChatApp, msg: Msg) -> Command { match msg { Msg::WsConnected(sender) => { app.ws_sender = Some(sender); app.messages.push("Connected!".into()); Command::none() } Msg::WsDisconnected => { app.ws_sender = None; app.messages.push("Disconnected".into()); Command::none() } Msg::WsReceived(text) => { app.messages.push(format!("Received: {}", text)); Command::none() } Msg::WsError(error) => { app.messages.push(format!("Error: {}", error)); Command::none() } } } fn subscriptions() -> Vec> { vec![ Subscription::new(WebSocket::new("wss://echo.websocket.org")) .map(|msg| match msg { WebSocketMessage::Connected { sender } => Msg::WsConnected(sender), WebSocketMessage::Disconnected => Msg::WsDisconnected, WebSocketMessage::Received(Message::Text(text)) => Msg::WsReceived(text.to_string()), WebSocketMessage::Error { error } => Msg::WsError(error), _ => Msg::WsError("Unexpected message type".into()), }), ] } ``` -------------------------------- ### Subscribe to Terminal Events in Rust Source: https://context7.com/akiomik/tears/llms.txt Demonstrates how to subscribe to terminal events such as keyboard input and window resizing. It maps raw terminal events to custom application messages and includes basic error handling. ```rust use tears::prelude::*; use tears::subscription::terminal::TerminalEvents; use crossterm::event::{Event, KeyCode, KeyEventKind}; enum Message { KeyPressed(char), Resize(u16, u16), InputError(std::io::Error), Quit, } fn subscriptions() -> Vec> { vec![ Subscription::new(TerminalEvents::new()).map(|result| match result { Ok(Event::Key(key)) if key.kind == KeyEventKind::Press => { match key.code { KeyCode::Char('q') => Message::Quit, KeyCode::Char(c) => Message::KeyPressed(c), _ => Message::KeyPressed(' '), } } Ok(Event::Resize(width, height)) => Message::Resize(width, height), Ok(_) => Message::KeyPressed(' '), Err(e) => Message::InputError(e), }), ] } ``` -------------------------------- ### Tears Application Trait Implementation (Rust) Source: https://github.com/akiomik/tears/blob/main/README.md Demonstrates the basic structure for implementing the `Application` trait in Tears. It includes placeholders for message types, initialization flags, state updates, UI rendering, and event subscriptions. ```rust use tears::prelude::*; use ratatui.Frame; struct App; enum Message {} impl Application for App { type Message = Message; // Your message type type Flags = (); // Initialization data (use () if none) // Initialize your app fn new(_flags: ()) -> (Self, Command) { (App, Command::none()) } // Handle messages and update state fn update(&mut self, _msg: Message) -> Command { Command::none() } // Render your UI fn view(&self, frame: &mut Frame) { // Use ratatui widgets here } // Subscribe to events (keyboard, timers, etc.) fn subscriptions(&self) -> Vec> { vec![] } } ``` -------------------------------- ### Mock Subscriptions for Testing with Tears Source: https://context7.com/akiomik/tears/llms.txt Utilizes `MockSource` for creating controllable subscription sources, enabling deterministic testing without real I/O or time dependencies. This is useful for testing application logic that relies on asynchronous data streams. ```rust use tears::prelude::*; use tears::subscription::mock::MockSource; use tears::subscription::Subscription; use ratatui::Frame; struct TestApp { count: u32, mock: MockSource, } impl Application for TestApp { type Message = u32; type Flags = MockSource; fn new(mock: MockSource) -> (Self, Command) { (Self { count: 0, mock }, Command::none()) } fn update(&mut self, msg: u32) -> Command { self.count += msg; Command::none() } fn view(&self, _frame: &mut Frame) {} fn subscriptions(&self) -> Vec> { vec![Subscription::new(self.mock.clone())] } } #[tokio::test] async fn test_counter_app() -> color_eyre::Result<()> { use futures::StreamExt; // Create a controllable mock let mock = MockSource::::new(); // Create subscription and get stream let sub = Subscription::new(mock.clone()); let mut stream = (sub.spawn)(); // Emit values from test mock.emit(10)?; mock.emit(20)?; mock.emit(30)?; // Verify values are received assert_eq!(stream.next().await, Some(10)); assert_eq!(stream.next().await, Some(20)); assert_eq!(stream.next().await, Some(30)); Ok(()) } // Test dynamic subscriptions based on state #[test] fn test_dynamic_subscriptions() { struct App { enabled: bool, mock: MockSource, } impl App { fn subscriptions(&self) -> Vec> { if self.enabled { vec![Subscription::new(self.mock.clone())] } else { vec![] } } } let mock = MockSource::new(); let app = App { enabled: true, mock: mock.clone() }; assert_eq!(app.subscriptions().len(), 1); let app = App { enabled: false, mock: mock.clone() }; assert_eq!(app.subscriptions().len(), 0); } ``` -------------------------------- ### Handle System Signals in Rust Source: https://context7.com/akiomik/tears/llms.txt Provides cross-platform signal handling for Unix (SIGINT, SIGTERM) and Windows (Ctrl+C). It uses conditional compilation to ensure the correct signal subscription is initialized based on the target operating system. ```rust #[cfg(unix)] use tears::subscription::{Subscription, signal::Signal}; #[cfg(unix)] use tokio::signal::unix::SignalKind; enum Message { Interrupted, Terminated, SignalError(std::io::Error), } #[cfg(unix)] fn signal_subscriptions() -> Vec> { vec![ Subscription::new(Signal::new(SignalKind::interrupt())) .map(|result| match result { Ok(()) => Message::Interrupted, Err(e) => Message::SignalError(e), }), Subscription::new(Signal::new(SignalKind::terminate())) .map(|result| match result { Ok(()) => Message::Terminated, Err(e) => Message::SignalError(e), }), ] } #[cfg(windows)] use tears::subscription::signal::{CtrlC, CtrlBreak}; #[cfg(windows)] fn windows_signal_subscriptions() -> Vec> { vec![ Subscription::new(CtrlC::new()).map(|result| match result { Ok(()) => Message::Interrupted, Err(e) => Message::SignalError(e), }), ] } ``` -------------------------------- ### Implement Custom Subscription Sources Source: https://context7.com/akiomik/tears/llms.txt Subscriptions handle ongoing event streams. By implementing the SubscriptionSource trait, users can define custom logic that produces messages until cancelled, with identity management via SubscriptionId. ```rust use tears::subscription::{Subscription, SubscriptionSource, SubscriptionId}; use tears::BoxStream; use futures::{StreamExt, stream}; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; enum Message { CustomEvent(String), } struct MySubscription { id: u64, prefix: String, } impl SubscriptionSource for MySubscription { type Output = String; fn stream(&self) -> BoxStream<'static, Self::Output> { let prefix = self.prefix.clone(); stream::iter(vec![ format!("{}: event 1", prefix), format!("{}: event 2", prefix), ]).boxed() } fn id(&self) -> SubscriptionId { let mut hasher = DefaultHasher::new(); self.id.hash(&mut hasher); SubscriptionId::of::(hasher.finish()) } } let sub = Subscription::new(MySubscription { id: 1, prefix: "test".into() }) .map(Message::CustomEvent); ``` -------------------------------- ### Perform HTTP Mutations with Tears Source: https://context7.com/akiomik/tears/llms.txt Demonstrates how to use the `Mutation` type in Tears for command-based data modifications (POST, PUT, PATCH, DELETE) via HTTP. Requires the 'http' feature to be enabled. Mutations are one-off operations that return a Command. ```rust // Enable with: tears = { version = "0.8", features = ["http"] } use std::sync::Arc; use tears::prelude::*; use tears::subscription::http::{Mutation, QueryClient, QueryError}; #[derive(Clone)] struct UserData { name: String, email: String, } #[derive(Clone)] struct User { id: u32, name: String, email: String, } enum Message { SubmitUser(UserData), UserCreated(User), CreateFailed(String), } struct App { query_client: Arc, status: String, } fn update(app: &mut App, msg: Message) -> Command { match msg { Message::SubmitUser(data) => { app.status = "Creating user...".into(); // Mutation returns Command> Mutation::mutate( data, |input| Box::pin(async move { // Perform HTTP request // In real app, use reqwest: // client.post("/api/users").json(&input).send().await Ok::(User { id: 1, name: input.name, email: input.email, }) }), ) .map(|result| match result { Ok(user) => Message::UserCreated(user), Err(e) => Message::CreateFailed(e.to_string()), }) } Message::UserCreated(user) => { app.status = format!("Created user: {}", user.name); // Invalidate cache to refetch user list app.query_client.invalidate(&"users") } Message::CreateFailed(error) => { app.status = format!("Failed: {}", error); Command::none() } } } ``` -------------------------------- ### Manage Asynchronous Side Effects with Commands Source: https://context7.com/akiomik/tears/llms.txt Commands are used to perform asynchronous operations like HTTP requests or file I/O. This snippet demonstrates creating, batching, and transforming commands using the tears::prelude module. ```rust use tears::prelude::*; use futures::stream; enum Message { DataLoaded(String), NumbersReceived(i32), BatchComplete, Error(String), } let cmd: Command = Command::none(); let cmd = Command::message(Message::BatchComplete); async fn fetch_data() -> Result { Ok("fetched data".to_string()) } let cmd = Command::perform(fetch_data(), |result| match result { Ok(data) => Message::DataLoaded(data), Err(e) => Message::Error(e), }); let cmd = Command::future(async { Message::DataLoaded("direct result".to_string()) }); let cmd: Command = Command::effect(Action::Quit); let cmd = Command::batch(vec![ Command::perform(async { 1 }, |n| Message::NumbersReceived(n)), Command::perform(async { 2 }, |n| Message::NumbersReceived(n)), ]); let numbers = stream::iter(vec![1, 2, 3]); let cmd = Command::run(numbers, |n| Message::NumbersReceived(n * 2)); let cmd: Command> = Command::future(async { Ok("data".to_string()) }); let cmd = cmd.map(|result| match result { Ok(s) => Message::DataLoaded(s), Err(e) => Message::Error(e), }); ``` -------------------------------- ### Enabling HTTP Support in Cargo.toml Source: https://github.com/akiomik/tears/blob/main/README.md Configuration snippet for `Cargo.toml` to enable HTTP support in the Tears project. It specifies the Tears version and the 'http' feature, which enables Query and Mutation subscriptions. ```toml [dependencies] tears = { version = "0.8", features = ["http"] } ``` -------------------------------- ### Configure Timer Subscriptions Source: https://context7.com/akiomik/tears/llms.txt The Timer subscription provides periodic tick messages. It is commonly used for animations or recurring background tasks, leveraging tokio intervals for accurate timing. ```rust use tears::subscription::{Subscription, time::{Timer, Message as TimerMessage}}; enum AppMessage { Tick, AnimationFrame, } let timer_sub = Subscription::new(Timer::new(1000)) .map(|msg| match msg { TimerMessage::Tick => AppMessage::Tick, }); let animation_timer = Subscription::new(Timer::new(16)) .map(|_| AppMessage::AnimationFrame); ``` -------------------------------- ### Enabling WebSocket Support in Cargo.toml Source: https://github.com/akiomik/tears/blob/main/README.md Configuration snippet for `Cargo.toml` to enable WebSocket support in the Tears project. It specifies the Tears version and the 'ws' feature, along with optional TLS backends. ```toml [dependencies] tears = { version = "0.8", features = ["ws", "rustls"] } ``` -------------------------------- ### Implement Application Trait in Rust Source: https://context7.com/akiomik/tears/llms.txt Defines a TUI application by implementing the Application trait, which requires defining the state (Model), message types, and lifecycle methods like update, view, and subscriptions. ```rust use color_eyre::eyre::Result; use crossterm::event::{Event, KeyCode}; use ratatui::Frame; use ratatui::text::Text; use tears::prelude::*; use tears::subscription::{terminal::TerminalEvents, time::{Timer, Message as TimerMessage}}; #[derive(Debug)] enum Message { Tick, Input(Event), InputError(String), } #[derive(Default)] struct Counter { count: u32, } impl Application for Counter { type Message = Message; type Flags = (); fn new(_flags: ()) -> (Self, Command) { (Counter::default(), Command::none()) } fn update(&mut self, msg: Message) -> Command { match msg { Message::Tick => { self.count += 1; Command::none() } Message::Input(Event::Key(key)) if key.code == KeyCode::Char('q') => { Command::effect(Action::Quit) } Message::InputError(e) => { eprintln!("Input error: {e}"); Command::effect(Action::Quit) } _ => Command::none(), } } fn view(&self, frame: &mut Frame) { let text = Text::raw(format!("Count: {} (Press 'q' to quit)", self.count)); frame.render_widget(text, frame.area()); } fn subscriptions(&self) -> Vec> { vec![ Subscription::new(Timer::new(1000)).map(|_| Message::Tick), Subscription::new(TerminalEvents::new()).map(|result| match result { Ok(event) => Message::Input(event), Err(e) => Message::InputError(e.to_string()), }), ] } } #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; let mut terminal = ratatui::init(); let runtime = Runtime::::new((), 60); let result = runtime.run(&mut terminal).await; ratatui::restore(); result?; Ok(()) } ``` -------------------------------- ### Tears Architecture Diagram Source: https://github.com/akiomik/tears/blob/main/README.md Visual representation of The Elm Architecture (TEA) pattern used by Tears. It illustrates the flow of data and control between Model, View, Update, Messages, Commands, and Subscriptions. ```text ┌──────────────────────────────────────────────┐ │ │ │ ┌─────────┐ ┌────────┐ ┌──────┐ │ │ │ Model │─────▶│ View │─────▶│ UI │ │ │ └─────────┘ └────────┘ └──────┘ │ │ ▲ │ │ │ │ │ ┌────┴─────┐ ┌──────────────┐ │ │ │ Update │◀────│ Messages │ │ │ └──────────┘ └──────────────┘ │ │ ▲ ▲ │ │ │ │ │ │ ┌────┴─────┐ ┌──────┴──────┐ │ │ │ Commands │ │Subscriptions│ │ │ └──────────┘ └─────────────┘ │ │ │ └──────────────────────────────────────────────┘ ``` -------------------------------- ### Compare Flamegraph Performance Source: https://github.com/akiomik/tears/blob/main/scripts/README.md Compares two flamegraph files to measure the impact of code optimizations. It calculates metric improvements or regressions across key areas like rendering, buffer diffing, and framework overhead. ```bash ./scripts/compare_flamegraphs.sh ``` -------------------------------- ### Generate Flamegraphs with Cargo Source: https://github.com/akiomik/tears/blob/main/scripts/README.md Commands to generate flamegraphs for Rust applications using cargo-flamegraph. Supports both debug builds for symbol detail and release builds for production performance metrics. ```bash # Debug build cargo flamegraph --example counter # Release build cargo flamegraph --release --example counter ``` -------------------------------- ### Analyze Flamegraph Performance Source: https://github.com/akiomik/tears/blob/main/scripts/README.md Analyzes a single flamegraph SVG file to identify performance bottlenecks, hotspots, and category-specific overhead. It outputs color-coded results to highlight critical, moderate, and minor performance issues. ```bash ./scripts/analyze_flamegraph.sh ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.