返回 CodeWhale
shell.rs
1 //! Portable slot geometry from Codewhale's `tui/ui/frame.rs`.
2 //! The conversation has no permanent header or side pane. The caller paints
3 //! pending input, composer, posture, workflow progress, metrics and work dock.
4 use crate::{Paint, Role, Theme};
5 use ratatui::{buffer::Buffer, layout::Rect};
6
7 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
8 pub struct ShellAreas {
9 pub conversation: Rect,
10 pub pending: Rect,
11 pub composer: Rect,
12 pub posture: Rect,
13 pub workflows: Rect,
14 pub metrics: Rect,
15 pub workbar: Rect,
16 }
17
18 #[derive(Clone, Copy, Debug)]
19 pub struct TerminalShell {
20 pub composer_rows: u16,
21 pub pending_rows: u16,
22 pub workflow_rows: u16,
23 pub workbar_rows: u16,
24 pub minimum_chat_rows: u16,
25 }
26 impl TerminalShell {
27 pub const fn new(composer_rows: u16) -> Self {
28 Self {
29 composer_rows,
30 pending_rows: 0,
31 workflow_rows: 0,
32 workbar_rows: 0,
33 minimum_chat_rows: 3,
34 }
35 }
36 pub const fn pending_rows(mut self, rows: u16) -> Self {
37 self.pending_rows = rows;
38 self
39 }
40 pub const fn workflow_rows(mut self, rows: u16) -> Self {
41 self.workflow_rows = rows;
42 self
43 }
44 pub const fn workbar_rows(mut self, rows: u16) -> Self {
45 self.workbar_rows = rows;
46 self
47 }
48 pub fn areas(&self, area: Rect) -> ShellAreas {
49 let composer = self.composer_rows.min(area.height);
50 let mut remaining = area.height.saturating_sub(composer);
51 let posture = remaining.min(1);
52 remaining = remaining.saturating_sub(posture);
53 let metrics = remaining.min(1);
54 remaining = remaining.saturating_sub(metrics);
55 let chat = remaining.min(self.minimum_chat_rows);
56 let mut auxiliary = remaining.saturating_sub(chat);
57 let dock = self.workbar_rows.min(auxiliary);
58 auxiliary = auxiliary.saturating_sub(dock);
59 let pending = self.pending_rows.min(4).min(auxiliary);
60 auxiliary = auxiliary.saturating_sub(pending);
61 let workflows = self.workflow_rows.min(auxiliary);
62 let conversation = remaining
63 .saturating_sub(dock)
64 .saturating_sub(pending)
65 .saturating_sub(workflows);
66 let mut y = area.y;
67 let mut slot = |height: u16| {
68 let rect = Rect::new(area.x, y, area.width, height);
69 y = y.saturating_add(height);
70 rect
71 };
72 ShellAreas {
73 conversation: slot(conversation),
74 pending: slot(pending),
75 composer: slot(composer),
76 posture: slot(posture),
77 workflows: slot(workflows),
78 metrics: slot(metrics),
79 workbar: slot(dock),
80 }
81 }
82 }
83 impl Paint for TerminalShell {
84 fn paint(&self, area: Rect, buf: &mut Buffer, theme: &Theme) {
85 buf.set_style(
86 area.intersection(buf.area),
87 theme.bg(Role::Background).patch(theme.fg(Role::Foreground)),
88 );
89 }
90 }
91
91 lines RUST