cli_tutor/ui/
free_practice_view.rs1use crate::app::{App, SubmitState};
3use crate::ui::input_bar;
4use ratatui::{
5 layout::{Constraint, Direction, Layout, Rect},
6 style::{Color, Modifier, Style},
7 text::{Line, Span},
8 widgets::{Block, Borders, Paragraph, Wrap},
9 Frame,
10};
11
12pub fn render(app: &App, frame: &mut Frame, area: Rect) {
13 let nc = app.config.no_color;
14
15 let chunks = Layout::default()
16 .direction(Direction::Vertical)
17 .constraints([
18 Constraint::Length(3), Constraint::Length(3), Constraint::Min(4), ])
22 .split(area);
23
24 let header = Paragraph::new(Line::from(vec![
26 Span::styled(
27 "Free Practice",
28 crate::ui::s(
29 Style::default()
30 .fg(Color::Cyan)
31 .add_modifier(Modifier::BOLD),
32 nc,
33 ),
34 ),
35 Span::raw(" — type any command and press Enter. No expected output is checked."),
36 ]))
37 .block(Block::default().borders(Borders::ALL));
38 frame.render_widget(header, chunks[0]);
39
40 input_bar::render(app, frame, chunks[1]);
42
43 let (output_text, output_style) = match app.submit_state {
45 SubmitState::Error => (
46 app.last_output
47 .as_ref()
48 .map(|o| format!("Error: {}", o.stderr))
49 .unwrap_or_else(|| "Error".to_string()),
50 crate::ui::s(Style::default().fg(Color::Yellow), nc),
51 ),
52 _ => {
53 let text = app
54 .last_output
55 .as_ref()
56 .map(|o| {
57 if o.timed_out {
58 "Command timed out after 3s".to_string()
59 } else if !o.stderr.is_empty() && o.stdout.is_empty() {
60 format!("stderr: {}", o.stderr)
61 } else {
62 o.stdout.clone()
63 }
64 })
65 .unwrap_or_default();
66 (text, Style::default())
67 }
68 };
69
70 let output_para = Paragraph::new(output_text)
71 .block(Block::default().borders(Borders::ALL).title("Output"))
72 .style(output_style)
73 .wrap(Wrap { trim: false })
74 .scroll((app.output_scroll, 0));
75 frame.render_widget(output_para, chunks[2]);
76}