markdown_demo/
markdown_demo.rs1use std::io::{self, Write};
2use std::thread;
3use std::time::{Duration, Instant};
4
5use eye_declare::{InlineRenderer, Markdown, Spinner, Text, VStack};
6use ratatui_core::style::{Color, Modifier, Style};
7
8fn main() -> io::Result<()> {
9 let (width, _) = crossterm::terminal::size()?;
10 let mut r = InlineRenderer::new(width);
11 let mut stdout = io::stdout();
12
13 let _prompt = r.push(Text::styled(
15 "› Explain how async/await works in Rust with an example",
16 Style::default()
17 .fg(Color::White)
18 .add_modifier(Modifier::BOLD),
19 ));
20 flush(&mut r, &mut stdout)?;
21
22 let _sp = r.push(Text::unstyled(""));
24
25 let response = r.push(VStack);
27
28 let think = r.append_child(response, Spinner::new("Thinking..."));
30 animate_spinner(&mut r, &mut stdout, think, Duration::from_millis(1200))?;
31 r.swap_component(think, Spinner::new("Thinking...").done("Thought for 1.2s"));
32 flush(&mut r, &mut stdout)?;
33 r.freeze(think);
34
35 let md_id = r.append_child(response, Markdown::new(""));
37
38 let response_text = r#"## Async/Await in Rust
39
40Rust's async/await is built on the **Future** trait. When you write an `async fn`, the compiler transforms it into a state machine that implements `Future`.
41
42### Key Concepts
43
44- **Futures are lazy** — they don't run until polled by an *executor*
45- The `await` keyword yields control back to the executor
46- An executor like `tokio` manages scheduling futures onto threads
47
48### Example
49
50```rust
51async fn fetch_data(url: &str) -> Result<String, Error> {
52 let response = reqwest::get(url).await?;
53 let body = response.text().await?;
54 Ok(body)
55}
56
57#[tokio::main]
58async fn main() {
59 let data = fetch_data("https://example.com").await;
60 println!("Got: {:?}", data);
61}
62```
63
64The `.await` points are where the runtime can **suspend** this task and run others. This is *cooperative* multitasking — tasks must explicitly yield via `await`."#;
65
66 let tokens: Vec<&str> = response_text
68 .split_inclusive(|c: char| c.is_whitespace() || c == '\n')
69 .collect();
70 let mut accumulated = String::new();
71 for token in &tokens {
72 accumulated.push_str(token);
73 r.swap_component(md_id, Markdown::new(accumulated.clone()));
74 flush(&mut r, &mut stdout)?;
75 thread::sleep(Duration::from_millis(20));
76 }
77
78 println!();
79 Ok(())
80}
81
82fn flush(r: &mut InlineRenderer, stdout: &mut impl Write) -> io::Result<()> {
83 let output = r.render();
84 if !output.is_empty() {
85 stdout.write_all(&output)?;
86 stdout.flush()?;
87 }
88 Ok(())
89}
90
91fn animate_spinner(
92 r: &mut InlineRenderer,
93 stdout: &mut impl Write,
94 id: eye_declare::NodeId,
95 duration: Duration,
96) -> io::Result<()> {
97 let start = Instant::now();
98 while start.elapsed() < duration {
99 r.state_mut::<Spinner>(id).tick();
100 flush(r, stdout)?;
101 thread::sleep(Duration::from_millis(80));
102 }
103 Ok(())
104}