(c: &ChangeReport)
| 394 | } |
| 395 | |
| 396 | fn render_change(c: &ChangeReport) -> String { |
| 397 | let cov = html_escape(&c.coverage); |
| 398 | let cov_class = match c.coverage.as_str() { |
| 399 | "covered" => "covered", |
| 400 | "uncovered" => "uncovered", |
| 401 | _ => "unknown", |
| 402 | }; |
| 403 | let (adds, dels) = diff_stat_counts(c); |
| 404 | let stat = if c.diff.is_empty() { |
| 405 | String::new() |
| 406 | } else { |
| 407 | format!( |
| 408 | " <span class=\"stat\">+{adds} -{dels} \u{00b7} {} file(s)</span>", |
| 409 | c.diff.len() |
| 410 | ) |
| 411 | }; |
| 412 | let mut s = String::new(); |
| 413 | // Collapsible, like intents — the summary conveys the change's shape while |
| 414 | // collapsed; the (potentially long) diff lives in the body. |
| 415 | s.push_str("<details class=\"change\">\n"); |
| 416 | s.push_str(&format!( |
| 417 | "<summary><code>{}</code> <span class=\"badge cov-{cov_class}\">{cov}</span>{stat}</summary>\n", |
| 418 | html_escape(&c.id) |
| 419 | )); |
| 420 | if !c.message.is_empty() { |
| 421 | s.push_str(&format!( |
| 422 | "<div class=\"change-msg\">{}</div>\n", |
| 423 | html_escape(&c.message) |
| 424 | )); |
| 425 | } |
| 426 | // Changed files: symbol + path + per-file hunk summary (no diff dump). |
| 427 | if !c.files.is_empty() { |
| 428 | s.push_str("<table class=\"files\">\n"); |
| 429 | for f in &c.files { |
| 430 | s.push_str(&format!( |
| 431 | "<tr><td class=\"sym\">{}</td><td><code>{}</code></td><td class=\"summary\">{}</td></tr>\n", |
| 432 | html_escape(&f.symbol), |
| 433 | html_escape(&f.path), |
| 434 | html_escape(&f.summary) |
| 435 | )); |
| 436 | } |
| 437 | s.push_str("</table>\n"); |
| 438 | } else if !c.modifies.is_empty() { |
| 439 | // Fallback (change not loadable): show the modified file-node ids. |
| 440 | s.push_str("<ul class=\"modifies\">\n"); |
| 441 | for m in &c.modifies { |
| 442 | s.push_str(&format!("<li><code>{}</code></li>\n", html_escape(m))); |
| 443 | } |
| 444 | s.push_str("</ul>\n"); |
| 445 | } |
| 446 | s.push_str(&format!( |
| 447 | "<div class=\"review-cmd\">inspect: <code>{}</code></div>\n", |
| 448 | html_escape(&c.review_command) |
| 449 | )); |
| 450 | // The real code-review surface: inline, color-coded unified diff. |
| 451 | for f in &c.diff { |
| 452 | s.push_str(&format!( |
| 453 | "<div class=\"diff-file\"><span class=\"diff-path\">{}</span> <span class=\"diff-status {}\">{}</span></div>\n", |
no test coverage detected