1use crate::event::Intent;
8use crate::pane::PaneId;
9use crate::tabs::nms::ConsoleState;
10use crate::view::{DrawCtx, Handled};
11use ratatui::Frame;
12use ratatui::layout::{Constraint, Direction, Layout, Rect};
13use ratatui::style::{Color, Modifier, Style};
14use ratatui::text::{Line, Span};
15use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
16
17fn draw_scrollback(state: &ConsoleState, frame: &mut Frame, area: Rect) {
18 let visible = usize::from(area.height);
19 let lines: Vec<Line> = state
20 .visible_scrollback(visible)
21 .iter()
22 .map(|l| Line::from(l.as_str()))
23 .collect();
24 frame.render_widget(Paragraph::new(lines).wrap(Wrap { trim: false }), area);
25}
26
27fn draw_prompt(state: &ConsoleState, frame: &mut Frame, area: Rect, focused: bool) {
28 let marker = if state.pending.is_empty() {
29 "nms> "
30 } else {
31 "...> "
32 };
33 let content = format!("{marker}{}", state.input.buffer());
34 let style = if focused {
35 Style::default()
36 .fg(Color::White)
37 .add_modifier(Modifier::BOLD)
38 } else {
39 Style::default().fg(Color::Gray)
40 };
41 frame.render_widget(Paragraph::new(Span::styled(content, style)), area);
42}
43
44fn draw_hint(frame: &mut Frame, area: Rect, active: bool, pane: PaneId) {
45 let hint = if active {
46 match pane {
47 PaneId::Scrollback => "Tab prompt Up/Down scroll PgUp/PgDn page Esc blur",
48 PaneId::Prompt => "Enter run Esc blur C-c interrupt Up/Down history",
49 }
50 } else {
51 "i/Enter focus 1-6 tabs Tab next q quit"
52 };
53 let line = Span::styled(hint, Style::default().fg(Color::DarkGray));
54 frame.render_widget(Paragraph::new(line), area);
55}
56
57impl ConsoleState {
58 pub fn draw(&self, frame: &mut Frame, area: Rect, ctx: &DrawCtx) {
59 let title = if ctx.is_active && self.panes.is_focused(PaneId::Scrollback) {
60 "Console — Scrollback ↕"
61 } else {
62 "Console"
63 };
64 let block = Block::default().borders(Borders::ALL).title(title);
65 let inner = block.inner(area);
66 frame.render_widget(block, area);
67
68 let chunks = Layout::default()
69 .direction(Direction::Vertical)
70 .constraints([
71 Constraint::Min(1),
72 Constraint::Length(1),
73 Constraint::Length(1),
74 ])
75 .split(inner);
76
77 draw_scrollback(self, frame, chunks[0]);
78 draw_prompt(
79 self,
80 frame,
81 chunks[1],
82 ctx.is_active && self.panes.is_focused(PaneId::Prompt),
83 );
84 draw_hint(frame, chunks[2], ctx.is_active, self.panes.focused());
85 }
86
87 pub fn handle(&mut self, _intent: Intent, _ctx: &DrawCtx) -> Handled {
88 Handled::Ignored
89 }
90}