Files
codex/prs/bolinfest/study/PR-1685-study.md
2025-09-02 15:17:45 -07:00

4.2 KiB
Raw Blame History

DOs

  • Alphasort feature lists: Keep Cargo feature arrays sorted for quick scanning.
# Cargo.toml
[dependencies]
ratatui = { version = "0.29.0", features = [
  "scrolling-regions",
  "unstable-rendered-line-info",
  "unstable-widget-ref",
] }
  • Surface public API first: Place pub items before helpers for faster discovery.
// insert_history.rs
pub(crate) fn insert_history_lines(term: &mut tui::Tui, lines: Vec<Line<'static>>) {
    // ...
}

fn write_spans(w: &mut impl Write, spans: impl Iterator<Item = &'_ Span<'_>>) -> io::Result<()> {
    // ...
}
  • Use clear, meaningful defaults (no magic numbers): Prefer named constants over hex literals.
let screen_height = term.backend().size().map(|s| s.height).unwrap_or(u16::MAX);
  • Finish comments and explain “why”: Make rationale explicit, not implied.
// We scroll one line at a time because terminals cannot place the cursor
// above the top of the visible screen. This guarantees every printed line
// lands within the valid region.
  • Handle modifier diffs symmetrically: Apply both removals and additions when changing styles.
let removed = from - to;
if removed.contains(Modifier::BOLD) { queue!(w, SetAttribute(CAttribute::NormalIntensity))?; }
if removed.contains(Modifier::ITALIC) { queue!(w, SetAttribute(CAttribute::NoItalic))?; }
// ... other removals

let added = to - from;
if added.contains(Modifier::BOLD) { queue!(w, SetAttribute(CAttribute::Bold))?; }
if added.contains(Modifier::ITALIC) { queue!(w, SetAttribute(CAttribute::Italic))?; }
// ... other additions
  • Reset styles after writing: Always restore terminal colors and attributes.
queue!(
    w,
    SetForegroundColor(CColor::Reset),
    SetBackgroundColor(CColor::Reset),
    SetAttribute(crossterm::style::Attribute::Reset),
)?;
  • If you own the type, enable exhaustive handling via iteration: Consider deriving iteration on your enum to cover all variants in tests.
# Cargo.toml
strum = "0.26"
strum_macros = "0.26"
use strum::IntoEnumIterator;
use strum_macros::EnumIter;

#[derive(EnumIter, Debug, Clone, Copy)]
enum MyStyle { Bold, Italic, Underline /* ... */ }

for s in MyStyle::iter() {
    // assert that s is handled
}

DONTs

  • Dont use Paragraph to wrap scrollback history: Let the terminal wrap; use scrolling regions and direct writes instead of a Buffer.
// ❌ Avoid
terminal.insert_before(total_lines, |buf| {
    Paragraph::new(line).render(area, buf);
});

// ✅ Prefer
terminal.backend_mut().scroll_region_up(0..top, 1)?;
terminal.set_cursor_position(Position::new(0, top - 1))?;
write_spans(&mut std::io::stdout(), line.iter())?;
  • Dont bury public functions below helpers: Avoid making readers hunt for the entry point.
// ❌ Helpers first, public last
fn helper_a() {}
fn helper_b() {}
pub(crate) fn insert_history_lines(...) {}
  • Dont leave comments unfinished or ambiguous: Remove placeholders like “unfini” and complete the thought.
// ❌ Incomplete
// We scroll up one line at a time because

// ✅ Complete
// We scroll one line at a time to avoid writing above the screen top.
  • Dont rely on unexplained magic numbers: Replace literals like 0xffffu16 with clear constants.
// ❌
let screen_height = size.map(|s| s.height).unwrap_or(0xffffu16);

// ✅
let screen_height = size.map(|s| s.height).unwrap_or(u16::MAX);
  • Dont partially update style state: Changing only added attributes (or only removed) causes drift.
// ❌ Only adds, never clears
if added.contains(Modifier::BOLD) { queue!(w, SetAttribute(CAttribute::Bold))?; }

// ✅ Apply removals and additions
let removed = from - to; /* clear removed */
let added = to - from;   /* set added  */
  • Dont add enum-iteration deps you cant use: strum helps only when you own the enum; for thirdparty bitflags, use explicit handling and tests instead.
// ❌ Adding strum to iterate a third-party bitflags type (wont work)

// ✅ Keep explicit mapping + tests around handled flags
assert!(handles_modifier(Modifier::BOLD));
assert!(handles_modifier(Modifier::ITALIC));