返回 CodeWhale
plan.rs
根目录 / crates / tui / src / tui / history / plan.rs
1 //! Rendering for plan-update transcript cells.
2
3 use ratatui::text::Line;
4
5 use crate::tools::plan::{PlanSnapshot, StepStatus};
6
7 use super::{
8 ToolStatus, render_compact_kv, render_tool_header, tool_status_label, tool_value_style,
9 };
10
11 /// Cell for plan updates emitted by the plan tool.
12 #[derive(Debug, Clone)]
13 pub struct PlanUpdateCell {
14 pub snapshot: PlanSnapshot,
15 pub status: ToolStatus,
16 }
17
18 impl PlanUpdateCell {
19 /// Render the plan update cell into lines.
20 pub fn lines_with_motion(&self, width: u16, low_motion: bool) -> Vec<Line<'static>> {
21 let mut lines = Vec::new();
22 lines.push(render_tool_header(
23 "Legacy plan",
24 tool_status_label(self.status),
25 self.status,
26 None,
27 low_motion,
28 ));
29
30 render_plan_snapshot_lines(&self.snapshot, &mut lines, width);
31
32 lines
33 }
34 }
35
36 fn render_plan_snapshot_lines(snapshot: &PlanSnapshot, lines: &mut Vec<Line<'static>>, width: u16) {
37 render_plan_optional(lines, "title", snapshot.title.as_deref(), width);
38 render_plan_optional(lines, "objective", snapshot.objective.as_deref(), width);
39 render_plan_optional(lines, "context", snapshot.context_summary.as_deref(), width);
40 render_plan_optional(lines, "explain", snapshot.explanation.as_deref(), width);
41 render_plan_list(lines, "source", &snapshot.sources_used, width);
42 render_plan_list(lines, "file", &snapshot.critical_files, width);
43 render_plan_list(lines, "constraint", &snapshot.constraints, width);
44 render_plan_optional(
45 lines,
46 "approach",
47 snapshot.recommended_approach.as_deref(),
48 width,
49 );
50 render_plan_optional(
51 lines,
52 "verify",
53 snapshot.verification_plan.as_deref(),
54 width,
55 );
56 render_plan_optional(lines, "risk", snapshot.risks_and_unknowns.as_deref(), width);
57 render_plan_optional(lines, "handoff", snapshot.handoff_packet.as_deref(), width);
58
59 for step in &snapshot.items {
60 let marker = match step.status {
61 StepStatus::Completed => "done",
62 StepStatus::InProgress => "live",
63 StepStatus::Pending => "next",
64 };
65 lines.extend(render_compact_kv(
66 marker,
67 &step.step,
68 tool_value_style(),
69 width,
70 ));
71 }
72 }
73
74 fn render_plan_optional(
75 lines: &mut Vec<Line<'static>>,
76 label: &str,
77 value: Option<&str>,
78 width: u16,
79 ) {
80 if let Some(value) = value.map(str::trim).filter(|value| !value.is_empty()) {
81 lines.extend(render_compact_kv(label, value, tool_value_style(), width));
82 }
83 }
84
85 fn render_plan_list(lines: &mut Vec<Line<'static>>, label: &str, values: &[String], width: u16) {
86 for value in values {
87 let value = value.trim();
88 if !value.is_empty() {
89 lines.extend(render_compact_kv(label, value, tool_value_style(), width));
90 }
91 }
92 }
93
93 lines RUST