|
1 | | -use anyhow::Result; |
2 | | -use colored::Colorize; |
3 | | - |
4 | | -use super::CommandContext; |
5 | | -use super::utils::{format_priority, format_status}; |
6 | | -use crate::assets::AssetManager; |
7 | | - |
8 | | -pub fn handle_show(ctx: &CommandContext, id: String, json: bool) -> Result<()> { |
9 | | - let pea = ctx.repo.get(&id)?; |
10 | | - |
11 | | - if json { |
12 | | - println!("{}", serde_json::to_string_pretty(&pea)?); |
13 | | - } else { |
14 | | - print_pea_with_refs(&pea, ctx); |
15 | | - } |
16 | | - Ok(()) |
17 | | -} |
18 | | - |
19 | | -fn print_pea_with_refs(pea: &crate::model::Pea, ctx: &CommandContext) { |
20 | | - println!("{} {}", pea.id.cyan().bold(), pea.title.bold()); |
21 | | - println!("Type: {}", format!("{}", pea.pea_type).blue()); |
22 | | - println!("Status: {}", format_status(pea.status)); |
23 | | - println!("Priority: {}", format_priority(pea.priority)); |
24 | | - |
25 | | - // Show parent with title if available |
26 | | - if let Some(parent_id) = &pea.parent { |
27 | | - let parent_info = if let Ok(parent_pea) = ctx.repo.get(parent_id) { |
28 | | - format!("{} ({})", parent_id.cyan(), parent_pea.title.dimmed()) |
29 | | - } else { |
30 | | - parent_id.cyan().to_string() |
31 | | - }; |
32 | | - println!("Parent: {}", parent_info); |
33 | | - } |
34 | | - |
35 | | - // Show blocking with titles if available |
36 | | - if !pea.blocking.is_empty() { |
37 | | - let blocking_info: Vec<String> = pea |
38 | | - .blocking |
39 | | - .iter() |
40 | | - .map(|id| { |
41 | | - if let Ok(blocked_pea) = ctx.repo.get(id) { |
42 | | - format!("{} ({})", id.cyan(), blocked_pea.title.dimmed()) |
43 | | - } else { |
44 | | - id.cyan().to_string() |
45 | | - } |
46 | | - }) |
47 | | - .collect(); |
48 | | - println!("Blocking: {}", blocking_info.join(", ")); |
49 | | - } |
50 | | - |
51 | | - if !pea.tags.is_empty() { |
52 | | - println!("Tags: {}", pea.tags.join(", ").magenta()); |
53 | | - } |
54 | | - |
55 | | - // Show assets if any |
56 | | - if !pea.assets.is_empty() { |
57 | | - let asset_manager = AssetManager::new(&ctx.root); |
58 | | - match asset_manager.list_assets(&pea.id) { |
59 | | - Ok(assets) => { |
60 | | - let asset_summary: Vec<String> = assets |
61 | | - .iter() |
62 | | - .map(|a| format!("{} ({})", a.filename, a.size_string())) |
63 | | - .collect(); |
64 | | - println!("Assets: {}", asset_summary.join(", ").yellow()); |
65 | | - } |
66 | | - Err(_) => { |
67 | | - // If we can't list assets, just show the filenames from frontmatter |
68 | | - println!("Assets: {}", pea.assets.join(", ").yellow()); |
69 | | - } |
70 | | - } |
71 | | - } |
72 | | - |
73 | | - println!( |
74 | | - "Created: {}", |
75 | | - pea.created.format("%Y-%m-%d %H:%M") |
76 | | - ); |
77 | | - println!( |
78 | | - "Updated: {}", |
79 | | - pea.updated.format("%Y-%m-%d %H:%M") |
80 | | - ); |
81 | | - |
82 | | - // Print body with resolved ticket references |
83 | | - if !pea.body.is_empty() { |
84 | | - let resolved_body = resolve_ticket_refs(&pea.body, &ctx.config.peas.prefix, ctx); |
85 | | - println!("\n{}", resolved_body); |
86 | | - } |
87 | | -} |
88 | | - |
89 | | -fn resolve_ticket_refs(text: &str, prefix: &str, ctx: &CommandContext) -> String { |
90 | | - use regex::Regex; |
91 | | - |
92 | | - // Build regex pattern for ticket IDs (e.g., peas-xxxxx) |
93 | | - let pattern = format!(r"({}[a-z0-9]+)", regex::escape(prefix)); |
94 | | - let re = match Regex::new(&pattern) { |
95 | | - Ok(r) => r, |
96 | | - Err(_) => return text.to_string(), |
97 | | - }; |
98 | | - |
99 | | - let mut result = text.to_string(); |
100 | | - let mut replacements = Vec::new(); |
101 | | - |
102 | | - // Find all ticket references and their titles |
103 | | - for cap in re.captures_iter(text) { |
104 | | - if let Some(m) = cap.get(1) { |
105 | | - let id = m.as_str(); |
106 | | - if let Ok(referenced_pea) = ctx.repo.get(id) { |
107 | | - replacements.push((id.to_string(), referenced_pea.title.clone())); |
108 | | - } |
109 | | - } |
110 | | - } |
111 | | - |
112 | | - // Replace references with annotated versions |
113 | | - for (id, title) in replacements { |
114 | | - let annotated = format!("{} ({})", id.cyan(), title.dimmed()); |
115 | | - result = result.replace(&id, &annotated); |
116 | | - } |
117 | | - |
118 | | - result |
119 | | -} |
| 1 | +use anyhow::Result; |
| 2 | +use colored::Colorize; |
| 3 | + |
| 4 | +use super::CommandContext; |
| 5 | +use super::utils::{format_priority, format_status}; |
| 6 | +use crate::assets::AssetManager; |
| 7 | + |
| 8 | +pub fn handle_show(ctx: &CommandContext, id: String, json: bool) -> Result<()> { |
| 9 | + let pea = ctx.repo.get(&id)?; |
| 10 | + |
| 11 | + if json { |
| 12 | + println!("{}", serde_json::to_string_pretty(&pea)?); |
| 13 | + } else { |
| 14 | + print_pea_with_refs(&pea, ctx); |
| 15 | + } |
| 16 | + Ok(()) |
| 17 | +} |
| 18 | + |
| 19 | +fn print_pea_with_refs(pea: &crate::model::Pea, ctx: &CommandContext) { |
| 20 | + println!("{} {}", pea.id.cyan().bold(), pea.title.bold()); |
| 21 | + println!("Type: {}", format!("{}", pea.pea_type).blue()); |
| 22 | + println!("Status: {}", format_status(pea.status)); |
| 23 | + println!("Priority: {}", format_priority(pea.priority)); |
| 24 | + |
| 25 | + // Show parent with title if available |
| 26 | + if let Some(parent_id) = &pea.parent { |
| 27 | + let parent_info = if let Ok(parent_pea) = ctx.repo.get(parent_id) { |
| 28 | + format!("{} ({})", parent_id.cyan(), parent_pea.title.dimmed()) |
| 29 | + } else { |
| 30 | + parent_id.cyan().to_string() |
| 31 | + }; |
| 32 | + println!("Parent: {}", parent_info); |
| 33 | + } |
| 34 | + |
| 35 | + // Show blocking with titles if available |
| 36 | + if !pea.blocking.is_empty() { |
| 37 | + let blocking_info: Vec<String> = pea |
| 38 | + .blocking |
| 39 | + .iter() |
| 40 | + .map(|id| { |
| 41 | + if let Ok(blocked_pea) = ctx.repo.get(id) { |
| 42 | + format!("{} ({})", id.cyan(), blocked_pea.title.dimmed()) |
| 43 | + } else { |
| 44 | + id.cyan().to_string() |
| 45 | + } |
| 46 | + }) |
| 47 | + .collect(); |
| 48 | + println!("Blocking: {}", blocking_info.join(", ")); |
| 49 | + } |
| 50 | + |
| 51 | + if !pea.tags.is_empty() { |
| 52 | + println!("Tags: {}", pea.tags.join(", ").magenta()); |
| 53 | + } |
| 54 | + |
| 55 | + // Show assets if any |
| 56 | + if !pea.assets.is_empty() { |
| 57 | + let asset_manager = AssetManager::new(&ctx.root); |
| 58 | + match asset_manager.list_assets(&pea.id) { |
| 59 | + Ok(assets) => { |
| 60 | + let asset_summary: Vec<String> = assets |
| 61 | + .iter() |
| 62 | + .map(|a| format!("{} ({})", a.filename, a.size_string())) |
| 63 | + .collect(); |
| 64 | + println!("Assets: {}", asset_summary.join(", ").yellow()); |
| 65 | + } |
| 66 | + Err(_) => { |
| 67 | + // If we can't list assets, just show the filenames from frontmatter |
| 68 | + println!("Assets: {}", pea.assets.join(", ").yellow()); |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + println!("Created: {}", pea.created.format("%Y-%m-%d %H:%M")); |
| 74 | + println!("Updated: {}", pea.updated.format("%Y-%m-%d %H:%M")); |
| 75 | + |
| 76 | + // Print body with resolved ticket references |
| 77 | + if !pea.body.is_empty() { |
| 78 | + let resolved_body = resolve_ticket_refs(&pea.body, &ctx.config.peas.prefix, ctx); |
| 79 | + println!("\n{}", resolved_body); |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +fn resolve_ticket_refs(text: &str, prefix: &str, ctx: &CommandContext) -> String { |
| 84 | + use regex::Regex; |
| 85 | + |
| 86 | + // Build regex pattern for ticket IDs (e.g., peas-xxxxx) |
| 87 | + let pattern = format!(r"({}[a-z0-9]+)", regex::escape(prefix)); |
| 88 | + let re = match Regex::new(&pattern) { |
| 89 | + Ok(r) => r, |
| 90 | + Err(_) => return text.to_string(), |
| 91 | + }; |
| 92 | + |
| 93 | + let mut result = text.to_string(); |
| 94 | + let mut replacements = Vec::new(); |
| 95 | + |
| 96 | + // Find all ticket references and their titles |
| 97 | + for cap in re.captures_iter(text) { |
| 98 | + if let Some(m) = cap.get(1) { |
| 99 | + let id = m.as_str(); |
| 100 | + if let Ok(referenced_pea) = ctx.repo.get(id) { |
| 101 | + replacements.push((id.to_string(), referenced_pea.title.clone())); |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + // Replace references with annotated versions |
| 107 | + for (id, title) in replacements { |
| 108 | + let annotated = format!("{} ({})", id.cyan(), title.dimmed()); |
| 109 | + result = result.replace(&id, &annotated); |
| 110 | + } |
| 111 | + |
| 112 | + result |
| 113 | +} |
0 commit comments