docs(comments): rewrite comments across all crates to the guidelines

Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
This commit is contained in:
ZacharyZhang-NY committed 2026-07-23 16:55:39 -04:00
1 parent ff0fb56c67
commit a02b555e66
1458 files changed
+10729 -21750

No files matched your search

@@ -59,7 +59,7 @@ pub fn indexed_to_rgb(index: u8) -> (u8, u8, u8) {
/// ramp (232–255), returning whichever has the smallest squared Euclidean
/// distance.
pub fn nearest_indexed(r: u8, g: u8, b: u8) -> u8 {
// --- nearest in the 6×6×6 color cube (16–231) ---
// nearest in the 6×6×6 color cube (16–231)
let ri = nearest_cube_channel(r);
let gi = nearest_cube_channel(g);
let bi = nearest_cube_channel(b);
@@ -73,7 +73,7 @@ pub fn nearest_indexed(r: u8, g: u8, b: u8) -> u8 {
CUBE_VALUES[bi as usize],
);
// --- nearest in the grayscale ramp (232–255) ---
// nearest in the grayscale ramp (232–255)
// Ramp values: 8, 18, 28, …, 238 (24 entries)
let lum = (r as u16 + g as u16 + b as u16) / 3;
let gray_step = if lum <= 3 {
@@ -131,7 +131,7 @@ fn color_to_rgb(color: Color) -> Option<(u8, u8, u8)> {
///
/// Useful when downstream code must produce RGB for *every* color value
/// — e.g. progress-bar gradients that lerp across named breakpoints, or
/// OSC 12 cursor-color updates that must emit an RGB triple regardless
/// OSC 12 cursor-color writes that must emit an RGB triple regardless
/// of terminal color depth.
///
/// Named-color RGB matches the xterm 16-color palette used by
@@ -166,11 +166,10 @@ pub fn resolve_to_rgb(color: Color) -> Option<(u8, u8, u8)> {
/// Blend a single color channel: lerp from base toward original based on opacity.
///
/// - `opacity = 0.0`: returns `base` (fully faded)
/// - `opacity = 1.0`: returns `original` (no change)
/// - `opacity = 1.0`: returns `original` (Unchanged)
#[inline]
pub fn blend_channel(base: u8, original: u8, opacity: f32) -> u8 {
// result = base + (original - base) * opacity
// = base * (1 - opacity) + original * opacity
let result = base as f32 * (1.0 - opacity) + original as f32 * opacity;
result.round() as u8
}
@@ -178,7 +177,7 @@ pub fn blend_channel(base: u8, original: u8, opacity: f32) -> u8 {
/// Blend a color toward a base color based on opacity.
///
/// - `opacity = 0.0`: returns `base` (fully faded)
/// - `opacity = 1.0`: returns `original` (no change)
/// - `opacity = 1.0`: returns `original` (Unchanged)
///
/// Supports both `Color::Rgb` and `Color::Indexed` colors (indexed colors are
/// converted to their RGB equivalents for blending). When either input is
@@ -212,9 +211,9 @@ pub fn blend_color(base: Color, original: Color, opacity: f32) -> Option<Color>
/// its colors toward the background.
///
/// - `opacity = 0.0`: fully faded to base color
/// - `opacity = 1.0`: no change (original colors)
/// - `opacity = 1.0`: Unchanged (original colors)
///
/// Named ANSI colors are left unchanged.
/// Named ANSI colors are left `unchanged`.
pub fn blend_line(line: Line<'static>, base: Color, opacity: f32) -> Line<'static> {
let blended_spans: Vec<Span<'static>> = line
.spans
@@ -239,9 +238,9 @@ pub fn blend_line(line: Line<'static>, base: Color, opacity: f32) -> Line<'stati
/// explicitly colored text.
///
/// - `opacity = 0.0`: fully faded to base color
/// - `opacity = 1.0`: no change (original colors)
/// - `opacity = 1.0`: Unchanged (original colors)
///
/// Named ANSI colors are left unchanged.
/// Named ANSI colors are left `unchanged`.
pub fn blend_line_with_default(
line: Line<'static>,
base: Color,
@@ -269,10 +268,10 @@ pub fn blend_line_with_default(
/// This blends both foreground and background colors of each cell toward
/// `base_color` based on `opacity`:
/// - `opacity = 0.0`: fully faded (cells become base_color)
/// - `opacity = 1.0`: no change
/// - `opacity = 1.0`: Unchanged
///
/// Both RGB and Indexed colors are blended; named ANSI colors (Color::Red, etc.)
/// are left unchanged since their RGB values are terminal-dependent.
/// are left `unchanged` since their RGB values are terminal-dependent.
pub fn fade_region(buf: &mut Buffer, area: Rect, base_color: Color, opacity: f32) {
blend_area(
buf,
@@ -285,10 +284,10 @@ pub fn fade_region(buf: &mut Buffer, area: Rect, base_color: Color, opacity: f32
/// Blend fg and/or bg of every cell in an area toward target colors.
///
/// Each parameter is `Option<(target, opacity)>`:
/// - `None`: leave that channel unchanged
/// - `None`: leave that channel `unchanged`
/// - `Some((target, opacity))`: blend toward `target` at `opacity`
/// - `opacity = 0.0`: fully target (original gone)
/// - `opacity = 1.0`: no change (original kept)
/// - `opacity = 1.0`: Unchanged (original kept)
///
/// Both RGB and Indexed colors are blended; named ANSI color cells are skipped.
pub fn blend_area(
@@ -383,7 +382,8 @@ mod tests {
// opacity = 0.5: halfway between
assert_eq!(blend_channel(0, 100, 0.5), 50);
assert_eq!(blend_channel(100, 200, 0.5), 150);
assert_eq!(blend_channel(0, 255, 0.5), 128); // 127.5 rounds to 128
// 127.5 rounds to 128
assert_eq!(blend_channel(0, 255, 0.5), 128);
}
#[test]
@@ -403,7 +403,7 @@ mod tests {
let faded = blend_color(base, original, 0.0);
assert_eq!(faded, Some(Color::Rgb(0, 0, 0)));
// No change
// Unchanged
let unchanged = blend_color(base, original, 1.0);
assert_eq!(unchanged, Some(Color::Rgb(100, 150, 200)));
@@ -415,8 +415,10 @@ mod tests {
#[test]
fn test_blend_color_indexed_returns_indexed() {
// Both indexed → result is indexed (quantized back to 256-color palette)
let base = Color::Indexed(232); // near-black (8, 8, 8)
let original = Color::Indexed(255); // near-white (238, 238, 238)
// near-black (8, 8, 8)
let base = Color::Indexed(232);
// near-white (238, 238, 238)
let original = Color::Indexed(255);
let half = blend_color(base, original, 0.5).unwrap();
assert!(matches!(half, Color::Indexed(_)));
@@ -433,7 +435,8 @@ mod tests {
#[test]
fn test_blend_color_mixed_returns_indexed() {
let rgb = Color::Rgb(100, 100, 100);
let indexed = Color::Indexed(5); // magenta (128, 0, 128)
// magenta (128, 0, 128)
let indexed = Color::Indexed(5);
// Mixed: indexed base + rgb original → Indexed result (quantized)
let result = blend_color(indexed, rgb, 0.5);
@@ -483,8 +486,8 @@ mod tests {
// Check cells are faded
if let Some(cell) = buf.cell((0, 0)) {
assert_eq!(cell.fg, Color::Rgb(100, 100, 100)); // 200 * 0.5
assert_eq!(cell.bg, Color::Rgb(25, 25, 25)); // 50 * 0.5
assert_eq!(cell.fg, Color::Rgb(100, 100, 100));
assert_eq!(cell.bg, Color::Rgb(25, 25, 25));
}
}
@@ -507,14 +510,14 @@ mod tests {
// Only fade a 2x2 region in the middle
fade_region(&mut buf, Rect::new(1, 1, 2, 2), base, 0.0);
// Corner should be unchanged
// Corner should be `unchanged`
assert_eq!(buf.cell((0, 0)).unwrap().fg, Color::Rgb(100, 100, 100));
// Middle should be fully faded
assert_eq!(buf.cell((1, 1)).unwrap().fg, Color::Rgb(0, 0, 0));
assert_eq!(buf.cell((2, 2)).unwrap().fg, Color::Rgb(0, 0, 0));
// Other corner unchanged
// Other corner `unchanged`
assert_eq!(buf.cell((3, 3)).unwrap().fg, Color::Rgb(100, 100, 100));
}
@@ -535,7 +538,7 @@ mod tests {
// fg blended to 50%
assert_eq!(buf.cell((0, 0)).unwrap().fg, Color::Rgb(100, 50, 0));
// bg unchanged
// bg `unchanged`
assert_eq!(buf.cell((0, 0)).unwrap().bg, Color::Rgb(10, 10, 10));
}
@@ -554,7 +557,7 @@ mod tests {
let target = Color::Rgb(0, 0, 0);
blend_area(&mut buf, Rect::new(0, 0, 2, 1), None, Some((target, 0.5)));
// fg unchanged
// fg `unchanged`
assert_eq!(buf.cell((0, 0)).unwrap().fg, Color::Rgb(200, 200, 200));
// bg blended to 50%
assert_eq!(buf.cell((0, 0)).unwrap().bg, Color::Rgb(50, 50, 50));
@@ -611,7 +614,8 @@ mod tests {
fn test_blend_area_named_color_skipped() {
let mut buf = Buffer::empty(Rect::new(0, 0, 1, 1));
if let Some(cell) = buf.cell_mut((0, 0)) {
cell.set_fg(Color::Red); // named color — blend_color returns None
// named color — blend_color returns None
cell.set_fg(Color::Red);
cell.set_bg(Color::Red);
}
@@ -622,7 +626,7 @@ mod tests {
Some((Color::Rgb(0, 0, 0), 0.5)),
);
// Named colors should be unchanged (blend_color returns None for them)
// Named colors should be `unchanged` (blend_color returns None for them)
assert_eq!(buf.cell((0, 0)).unwrap().fg, Color::Red);
assert_eq!(buf.cell((0, 0)).unwrap().bg, Color::Red);
}
@@ -631,12 +635,14 @@ mod tests {
fn test_blend_area_indexed_colors_blended() {
let mut buf = Buffer::empty(Rect::new(0, 0, 1, 1));
if let Some(cell) = buf.cell_mut((0, 0)) {
cell.set_fg(Color::Indexed(255)); // near-white grayscale
// near-white grayscale
cell.set_fg(Color::Indexed(255));
cell.set_bg(Color::Indexed(255));
}
// Blend toward black (indexed 232 = #080808, but we use indexed 16 = #000000)
let target = Color::Indexed(16); // black in the color cube
// black in the color cube
let target = Color::Indexed(16);
blend_area(
&mut buf,
Rect::new(0, 0, 1, 1),
@@ -368,7 +368,7 @@ pub fn draw_frame(
#[cfg(test)]
mod tests {
use super::*;
/// An unchanged frame must emit zero bytes to the PTY.
/// An `unchanged` frame must emit zero bytes to the PTY.
#[test]
fn idle_frame_emits_zero_bytes() {
use ratatui::backend::CrosstermBackend;
@@ -12,8 +12,7 @@ use ratatui::widgets::{Block, BorderType, Borders, Widget};
use crate::gboom::GboomHud;
use crate::render::safe_buf::SafeBuf;
/// Render the GBOOM popup chrome. Returns the popup `Rect`,
/// or `None` if the area is too small to play in.
/// Returns the popup `Rect`, or `None` when the area is too small to play in.
pub fn render_gboom_overlay(
buf: &mut Buffer,
area: Rect,
@@ -28,7 +27,6 @@ pub fn render_gboom_overlay(
crate::render::color::dim_area(buf, area, bg, 0.5);
// 90% centered popup, like the video viewer.
let popup_width = ((area.width as u32 * 90) / 100)
.max(30)
.min(area.width as u32) as u16;
@@ -49,7 +47,6 @@ pub fn render_gboom_overlay(
.style(Style::default().bg(bg))
.render(popup_rect, buf);
// Title centered in the top border, in the iconic logo red.
let title = " GBOOM ";
let [r, g, b] = crate::gboom::GBOOM_RED;
let title_style = Style::default()
@@ -60,14 +57,13 @@ pub fn render_gboom_overlay(
let tx = popup_rect.x + (popup_rect.width.saturating_sub(tw)) / 2;
buf.set_span_safe(tx, popup_rect.y, &Span::styled(title, title_style), tw);
// HUD on the bottom border row.
render_hud_bar(buf, popup_rect, hud, border_fg, bg);
Some(popup_rect)
}
/// Render the HUD on the popup's bottom border row:
/// `HP 100 · KILLS 0/8` left, controls hint right.
/// Overwrites the popup's bottom border row: `HP 100 · KILLS 0/8` on the left,
/// controls hint on the right.
fn render_hud_bar(buf: &mut Buffer, popup_rect: Rect, hud: &GboomHud, dim_fg: Color, bg: Color) {
let bar_y = popup_rect.y + popup_rect.height.saturating_sub(1);
let inner_width = popup_rect.width.saturating_sub(2) as usize;
@@ -75,8 +71,7 @@ fn render_hud_bar(buf: &mut Buffer, popup_rect: Rect, hud: &GboomHud, dim_fg: Co
return;
}
// Health-bar semantics: green when comfortable, amber when hurting,
// GBOOM red when critical.
// Green when comfortable, amber when hurting, GBOOM red when critical.
let hp_color = if hud.hp > 60 {
Color::Rgb(126, 200, 96)
} else if hud.hp > 30 {
@@ -70,8 +70,8 @@ pub fn paint_match_highlights(
}
}
/// Apply the terminal's REVERSED attribute so the fg/bg swap is native and
/// respects the user's theme.
/// REVERSED leaves the fg/bg swap to the terminal, so highlights follow the
/// user's theme instead of hardcoded colors.
fn invert_cell(cell: &mut ratatui::buffer::Cell) {
cell.modifier.insert(ratatui::style::Modifier::REVERSED);
}
@@ -17,6 +17,7 @@ pub(super) fn paint_path_line(
bg: Color,
) {
let raw = path.display().to_string();
// The 6 reserved columns are the "Path: " prefix.
let label = format!(
"Path: {}",
truncate_path_for_overlay(&raw, width.saturating_sub(6) as usize)
@@ -109,7 +109,7 @@ pub fn truncate_str(s: &str, max_width: usize) -> String {
/// exhausted mid-span, that span is truncated and `…` is appended. Spans
/// beyond the budget are dropped. All styles are preserved.
///
/// Returns the line unchanged if it already fits.
/// Returns the line `unchanged` if it already fits.
pub fn truncate_line(line: Line<'static>, max_width: usize) -> Line<'static> {
if max_width == 0 {
return Line::from(vec![]);
@@ -152,7 +152,7 @@ pub fn truncate_line(line: Line<'static>, max_width: usize) -> Line<'static> {
/// Clip or pad a styled `Line` to exactly `width` display columns.
///
/// Wider lines are clipped on grapheme boundaries (a multi-`char` grapheme like
/// `⚠\u{FE0F}` is never split) with no ellipsis; narrower lines are padded with
/// `⚠\u{FE0F}` is never split) with no ellipsis; narrower lines are `padded` with
/// trailing spaces. This keeps a rendered row "self-owning" — the app writes a
/// real cell in every column, so a terminal drawing a glyph wider than the app
/// measured cannot strand a stale cell past the row (the markdown-table ghost
@@ -346,10 +346,11 @@ mod tests {
let s = "hello — world";
let result = truncate_str(s, 8);
assert!(result.ends_with('…'));
assert!(result.len() <= 12); // safe byte length
// safe byte length
assert!(result.len() <= 12);
}
// ── truncate_line tests ─────────────────────────────────────────
// truncate_line tests
#[test]
fn truncate_line_fits() {
@@ -395,7 +396,7 @@ mod tests {
assert!(result.spans.is_empty());
}
// ── fit_line_to_width tests ─────────────────────────────────────
// fit_line_to_width tests
fn line_text(line: &Line<'static>) -> String {
line.spans.iter().map(|s| s.content.as_ref()).collect()
@@ -438,7 +439,7 @@ mod tests {
#[test]
fn fit_line_clips_grapheme_straddle_in_later_span() {
// The straddle happens in a later span: keep "ab", then 1 col left →
// ⚠️ (width 2) won't fit → dropped whole and padded.
// ⚠️ (width 2) won't fit → dropped whole and `padded`.
let line = Line::from(vec![Span::raw("ab"), Span::raw("\u{26A0}\u{FE0F}cd")]);
let out = fit_line_to_width(line, 3);
assert_eq!(line_text(&out).width(), 3);
@@ -502,7 +503,7 @@ mod tests {
);
}
// ── cascade_truncate tests ────────────────────────────────────
// cascade_truncate tests
#[test]
fn cascade_truncate_all_fit() {
@@ -1,6 +1,4 @@
//! Low-level rendering utilities.
//!
//! Generic rendering primitives used by the scrollback and viewport.
//! Low-level rendering primitives shared by the scrollback and viewport.
pub mod color;
pub mod draw;
pub mod gboom_overlay;
@@ -48,7 +48,8 @@ impl LinkOverlay {
link.col_end
);
if link.col_start > link.col_end {
return; // Silently skip inverted ranges in release mode.
// Silently skip inverted ranges in release mode.
return;
}
self.links.push(link);
}
@@ -541,7 +542,7 @@ mod tests {
scan_lines_for_url_overlays(rows.into_iter(), content_x, media_paths, overlay);
}
// ── local_link_to_file_url ──
// local_link_to_file_url
#[test]
fn local_link_relative_resolves_to_generated_media() {
@@ -592,7 +593,7 @@ mod tests {
assert!(local_link_to_file_url("../images/1.jpg", &media).is_none());
}
// ── tool_path_file_url ──
// tool_path_file_url
#[test]
fn tool_path_file_url_resolves_relative_against_cwd() {
@@ -637,7 +638,7 @@ mod tests {
);
}
// ── LinkOverlay ──
// LinkOverlay
#[test]
fn overlay_empty_by_default() {
@@ -661,7 +662,7 @@ mod tests {
assert_eq!(overlay.links()[0].screen_row, 5);
}
// ── scan_lines_for_url_overlays ──
// scan_lines_for_url_overlays
use ratatui::text::{Line as RLine, Span as RSpan};
@@ -690,7 +691,8 @@ mod tests {
assert_eq!(link.screen_row, 5);
// "See " = 4 display cols, content_x = 2
assert_eq!(link.col_start, 6);
assert_eq!(link.col_end, 6 + 19); // "https://example.com" = 19 chars
// "https://example.com" = 19 chars
assert_eq!(link.col_end, 6 + 19);
assert_eq!(link.id, None);
}
@@ -796,7 +798,7 @@ mod tests {
assert_eq!(overlay.links()[0].col_end, 10 + 16);
}
// ── File path detection ──
// File path detection
#[test]
fn scan_detects_absolute_file_path() {
@@ -875,7 +877,7 @@ mod tests {
#[test]
fn scan_detects_media_path_soft_wrapped_across_rows() {
// Regression: media-tool output prose wraps the long session path
// across visual rows (`joiner: Some("")` mid-word break). Previously
// across visual rows (`joiner: Some("")` mid-word break). earlier
// each row was scanned in isolation, so only the `/Users/alice`
// fragment on the first row matched and became clickable.
let row0 =
@@ -1162,7 +1164,7 @@ mod tests {
&*overlay.links()[0].url,
"file:///tmp/release/Demo%20App.app"
);
assert_eq!(overlay.links()[0].col_start, 5); // "open "
assert_eq!(overlay.links()[0].col_start, 5);
assert_eq!(
overlay.links()[0].col_end,
5 + UnicodeWidthStr::width(path) as u16
@@ -1184,7 +1186,7 @@ mod tests {
assert_eq!(overlay.links()[0].col_end, 4 + 12);
}
// ── Home-relative (`~/`) path detection ──
// Home-relative (`~/`) path detection
#[test]
fn scan_detects_tilde_file_path() {
@@ -1277,7 +1279,7 @@ mod tests {
id: None,
});
assert!(overlay.overlaps(5, 10, 20));
assert!(!overlay.overlaps(6, 10, 20)); // different row
assert!(!overlay.overlaps(6, 10, 20));
}
#[test]
@@ -1290,10 +1292,11 @@ mod tests {
url: Arc::from("https://a.example"),
id: None,
});
assert!(overlay.overlaps(0, 15, 25)); // right overlap
assert!(overlay.overlaps(0, 5, 15)); // left overlap
assert!(!overlay.overlaps(0, 20, 30)); // adjacent, no overlap
assert!(!overlay.overlaps(0, 0, 10)); // adjacent left
assert!(overlay.overlaps(0, 15, 25));
assert!(overlay.overlaps(0, 5, 15));
// adjacent, no overlap
assert!(!overlay.overlaps(0, 20, 30));
assert!(!overlay.overlaps(0, 0, 10));
}
#[test]
@@ -17,9 +17,7 @@ use ratatui::widgets::{Block, BorderType, Borders, Clear, Widget};
use super::line_utils::{truncate_line, truncate_str};
use super::safe_buf::SafeBuf;
// ---------------------------------------------------------------------------
// PreviewStyle — configurable colors
// ---------------------------------------------------------------------------
/// Visual styling for the preview overlay.
#[derive(Debug, Clone, Copy)]
@@ -43,9 +41,7 @@ impl PreviewStyle {
}
}
// ---------------------------------------------------------------------------
// PreviewConfig — layout configuration
// ---------------------------------------------------------------------------
/// Layout configuration for the preview overlay.
#[derive(Debug, Clone)]
@@ -89,9 +85,7 @@ impl Default for PreviewConfig {
}
}
// ---------------------------------------------------------------------------
// render_preview_overlay — main rendering function
// ---------------------------------------------------------------------------
/// Render a multiline preview overlay.
///
@@ -129,7 +123,8 @@ pub fn render_preview_overlay(
// Calculate content layout
let needs_dots = total > config.preview_lines * 2;
let content_lines: usize = if needs_dots {
config.preview_lines * 2 + 1 // top + dots + bottom
// top + dots + bottom
config.preview_lines * 2 + 1
} else {
total
};
@@ -255,7 +250,7 @@ fn render_line(buf: &mut Buffer, x: u16, y: u16, width: u16, line: &str, style:
}
/// Paint the hint into the bottom border row, left-aligned after the
/// corner and one dash, padded with a space on each side so the text
/// corner and one dash, `padded` with a space on each side so the text
/// stands off the dashes: `╰─ enter to expand ────╯`. The corners and
/// one dash per side are never overwritten. Skipped entirely when the
/// box is too narrow for readable text.
@@ -283,9 +278,7 @@ fn render_border_hint(buf: &mut Buffer, box_area: Rect, hint: &Line<'static>, bg
buf.set_line_safe(box_area.x + 2, y, &Line::from(spans), box_area.width - 4);
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
#[cfg(test)]
mod tests {
@@ -293,9 +286,12 @@ mod tests {
fn test_style() -> PreviewStyle {
PreviewStyle::new(
Color::Indexed(234), // grayscale 28 — dark bg
Color::Indexed(189), // (215,215,255) — light text
Color::Indexed(60), // (95,95,135) — dim border
// grayscale 28 — dark bg
Color::Indexed(234),
// (215,215,255) — light text
Color::Indexed(189),
// (95,95,135) — dim border
Color::Indexed(60),
)
}
@@ -317,7 +313,8 @@ mod tests {
let mut buf = Buffer::empty(Rect::new(0, 0, 10, 3));
let result = render_preview_overlay(
&mut buf,
Rect::new(0, 0, 10, 3), // below min_height=5
// below min_height=5
Rect::new(0, 0, 10, 3),
"hello\nworld",
test_style(),
PreviewConfig::default(),
@@ -435,7 +432,7 @@ mod tests {
);
assert!(result.is_some());
let rect = result.unwrap();
assert_eq!(rect.width, 50); // 100 * 0.5 = 50
assert_eq!(rect.width, 50);
}
#[test]
@@ -57,9 +57,7 @@ impl<'a> From<Box<dyn Renderable + 'a>> for RenderableItem<'a> {
}
}
// ============================================================================
// Standard Implementations
// ============================================================================
/// Unit type renders as nothing (0 height).
impl Renderable for () {
@@ -6,25 +6,19 @@
//! a crash.
//!
//! This extension trait provides `set_line_safe` / `set_span_safe` /
//! `set_string_safe` that silently skip the write when `y` is outside the
//! buffer — trading a single missed frame for a panic-free resize.
//! `set_string_safe`, which skip the write when the target row lies outside
//! the buffer or `x` is past its right edge — trading a single missed frame
//! for a panic-free resize.
use ratatui::buffer::Buffer;
use ratatui::style::Style;
use ratatui::text::{Line, Span};
/// Extension trait for bounds-checked buffer writes.
pub trait SafeBuf {
/// Like `Buffer::set_line` but returns immediately when `y` is outside
/// the buffer area.
fn set_line_safe(&mut self, x: u16, y: u16, line: &Line<'_>, width: u16);
/// Like `Buffer::set_span` but returns immediately when `y` is outside
/// the buffer area.
fn set_span_safe(&mut self, x: u16, y: u16, span: &Span<'_>, width: u16);
/// Like `Buffer::set_string` but returns immediately when `y` is outside
/// the buffer area.
fn set_string_safe<S: AsRef<str>>(&mut self, x: u16, y: u16, string: S, style: Style);
}
@@ -76,7 +76,7 @@ pub const SCROLLBAR_TOTAL_COLS: u16 = SCROLLBAR_GAP_COLS + SCROLLBAR_TRACK_COLS;
/// Layout:
/// - `content_area`: original area minus [`SCROLLBAR_TOTAL_COLS`] on the right
/// - `scrollbar_area`: the last column of the original area (1 cell wide)
/// - The column between them is the "gap" (left intentionally blank)
/// - The column between them is the "gap" (left deliberately blank)
///
/// Returns `(content_area, None)` when the terminal is too narrow.
///
@@ -126,7 +126,8 @@ pub fn needs_scrollbar(total_lines: u16, viewport_lines: u16) -> bool {
}
/// Whether the view is at the bottom (following mode position).
#[allow(dead_code)] // Useful helper, kept for future use
// Useful helper, kept for future use
#[allow(dead_code)]
pub fn is_at_bottom(total_lines: u16, viewport_lines: u16, offset: u16) -> bool {
let max_offset = total_lines.saturating_sub(viewport_lines);
offset >= max_offset
@@ -384,7 +385,8 @@ mod tests {
// Content overflows (20 > 10) - should reserve scrollbar space
let (content, scrollbar) = maybe_split_for_scrollbar(area, 20);
assert_eq!(content.width, 38); // Reduced by 2 for gap + scrollbar track
// Reduced by 2 for gap + scrollbar track
assert_eq!(content.width, 38);
assert!(scrollbar.is_some());
}
@@ -394,24 +396,29 @@ mod tests {
// Content fits (5 <= 10) - should give full width to content
let (content, scrollbar) = maybe_split_for_scrollbar(area, 5);
assert_eq!(content.width, 40); // Full width
assert_eq!(content.width, 40);
assert!(scrollbar.is_none());
}
#[test]
fn test_needs_scrollbar() {
assert!(needs_scrollbar(100, 10)); // Content > viewport
assert!(!needs_scrollbar(10, 10)); // Content == viewport
assert!(!needs_scrollbar(5, 10)); // Content < viewport
// Content > viewport
assert!(needs_scrollbar(100, 10));
// Content == viewport
assert!(!needs_scrollbar(10, 10));
// Content < viewport
assert!(!needs_scrollbar(5, 10));
}
#[test]
fn test_is_at_bottom() {
// total=100, viewport=10 -> max_offset=90
assert!(is_at_bottom(100, 10, 90)); // At bottom
assert!(is_at_bottom(100, 10, 95)); // Past bottom (clamped)
assert!(!is_at_bottom(100, 10, 89)); // One line above bottom
assert!(!is_at_bottom(100, 10, 0)); // At top
assert!(is_at_bottom(100, 10, 90));
// Past bottom (clamped)
assert!(is_at_bottom(100, 10, 95));
// One line above bottom
assert!(!is_at_bottom(100, 10, 89));
assert!(!is_at_bottom(100, 10, 0));
}
#[test]
@@ -258,7 +258,6 @@ fn first_param(params: &Params, default: u16) -> u16 {
}
}
/// Map a 0-7 ANSI color index to a named ratatui color.
fn ansi16(n: u16) -> Color {
match n {
0 => Color::Black,
@@ -272,7 +271,6 @@ fn ansi16(n: u16) -> Color {
}
}
/// Map a 0-7 bright ANSI color index to a named ratatui color.
fn ansi16_bright(n: u16) -> Color {
match n {
0 => Color::DarkGray,
@@ -7,7 +7,6 @@ use unicode_width::UnicodeWidthStr;
use super::line_utils::truncate_str;
/// Read/Edit tool-header path paint surface.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ToolPathSurface {
/// Basename only.
@@ -183,7 +182,6 @@ pub fn path_basename(path: &str, budget: usize) -> String {
truncate_str(name, budget)
}
/// Compatibility formatter: compact basename with `Some(width)`, else stored path.
pub fn path_for_tool_header(path: &str, width: Option<usize>, reserved: usize) -> String {
match width {
Some(width) => path_basename(path, width.saturating_sub(reserved)),
@@ -191,7 +189,6 @@ pub fn path_for_tool_header(path: &str, width: Option<usize>, reserved: usize) -
}
}
/// Path text for a Read/Edit tool-header surface.
pub fn path_for_tool_surface(
path: &str,
surface: ToolPathSurface,
@@ -12,8 +12,6 @@ use ratatui::widgets::{Block, BorderType, Borders, Widget};
use crate::prompt_images::VideoViewerState;
use crate::render::safe_buf::SafeBuf;
/// Render the video viewer popup chrome. Returns the popup `Rect`,
/// or `None` if the area is too small.
pub fn render_video_overlay(
buf: &mut Buffer,
area: Rect,
@@ -28,7 +26,6 @@ pub fn render_video_overlay(
crate::render::color::dim_area(buf, area, bg, 0.5);
// 90% centered popup.
let popup_width = ((area.width as u32 * 90) / 100)
.max(28)
.min(area.width as u32) as u16;
@@ -49,7 +46,6 @@ pub fn render_video_overlay(
.style(Style::default().bg(bg))
.render(popup_rect, buf);
// Title centered in top border.
let title = match viewer.title {
Some(ref name) => format!(
" {} ({}\u{00d7}{}) ",
@@ -68,13 +64,11 @@ pub fn render_video_overlay(
let tx = popup_rect.x + (popup_rect.width.saturating_sub(tw)) / 2;
buf.set_span_safe(tx, popup_rect.y, &Span::styled(&title, title_style), tw);
// Progress bar on the bottom border row.
render_progress_bar(buf, popup_rect, viewer, text_fg, border_fg, bg);
Some(popup_rect)
}
/// Render the progress bar on the popup's bottom border row.
fn render_progress_bar(
buf: &mut Buffer,
popup_rect: Rect,
@@ -114,7 +114,8 @@ pub(crate) fn byte_offset_to_display_col(text: &str, byte_offset: usize) -> usiz
/// forward. If a future change to the wrapping pipeline breaks this
/// invariant, consider switching to a two-stage approach that mirrors
/// `word_wrap_line_with_joiners` exactly.
#[allow(clippy::single_range_in_vec_init)] // intentional: single range = full text, no wrapping
// intentional: single range = full text, no wrapping
#[allow(clippy::single_range_in_vec_init)]
pub fn wrap_byte_ranges_matching(text: &str, width: usize) -> Vec<Range<usize>> {
if width == 0 || text.is_empty() {
return vec![0..text.len()];
@@ -362,7 +363,7 @@ fn is_table_line(line: &Line<'_>) -> bool {
/// this wrap layer re-injecting the prefix spans (with their styles) on
/// continuation rows, so keep the two shapes in agreement.
fn blockquote_prefix_len(flat: &str) -> usize {
const BAR_BYTES: usize = '\u{2502}'.len_utf8(); // 3
const BAR_BYTES: usize = '\u{2502}'.len_utf8();
let mut len = 0;
let mut chars = flat.chars();
while let Some('\u{2502}') = chars.next() {
@@ -1187,14 +1188,15 @@ mod tests {
}
}
// -- byte_range_to_row_cols tests -----------------------------------------
// byte_range_to_row_cols tests
#[test]
fn highlight_single_row_match() {
// "hello world" on one row (no wrapping).
let text = "hello world";
let ranges = vec![0..11]; // one row, full text
let segments = byte_range_to_row_cols(text, &ranges, 6..11); // "world"
// one row, full text
let ranges = vec![0..11];
let segments = byte_range_to_row_cols(text, &ranges, 6..11);
assert_eq!(
segments,
vec![HighlightSegment {
@@ -1306,8 +1308,9 @@ mod tests {
// Byte layout: a(1) b(1) —(3) c(1) d(1) = 7 bytes total.
// Display: a(0) b(1) —(2) c(3) d(4) = 5 display columns.
let text = "ab\u{2014}cd";
assert_eq!(text.len(), 7); // 2 + 3 + 2 bytes
let ranges = vec![0..7]; // one row
// 2 + 3 + 2 bytes
assert_eq!(text.len(), 7);
let ranges = vec![0..7];
// Match "cd" = bytes 5..7, display cols 3..5.
let segments = byte_range_to_row_cols(text, &ranges, 5..7);
assert_eq!(
@@ -1340,7 +1343,7 @@ mod tests {
);
}
// -- Table line detection / no-wrap tests ----------------------------------
// Table line detection / no-wrap tests
#[test]
fn table_line_box_drawing_not_wrapped() {
@@ -1362,14 +1365,15 @@ mod tests {
assert_eq!(joiners, vec![None]);
}
/// Regression: a table row narrower than the content width must be padded
/// Regression: a table row narrower than the content width must be `padded`
/// so the app owns every column (otherwise a wide-glyph width disagreement
/// strands a ghost cell).
#[test]
fn table_row_padded_to_content_width() {
use unicode_width::UnicodeWidthStr;
let line = Line::from("│ Status │ Note │"); // 23 display columns
// 23 display columns
let line = Line::from("│ Status │ Note │");
assert_eq!(concat_line(&line).width(), 23);
let content_width = 40;
@@ -1390,7 +1394,7 @@ mod tests {
/// Faithful repro: a body row with an emoji-presentation sequence
/// (`⚠\u{FE0F}`) and an em-dash — the glyphs that desynced the cursor — must
/// be padded to exactly the content width.
/// be `padded` to exactly the content width.
#[test]
fn table_row_with_emoji_and_em_dash_fills_content_width() {
use unicode_width::UnicodeWidthStr;