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

120 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**DOs**
- Factor layout logic into a helper: centralize the split between the transient “active history cell” and the bottom pane, and reuse it in both `cursor_pos()` and `render_ref()`.
```rust
impl ChatWidget<'_> {
fn layout_areas(&self, area: Rect) -> [Rect; 2] {
Layout::vertical([
Constraint::Max(
self.active_history_cell
.as_ref()
.map_or(0, |c| c.desired_height(area.width)),
),
Constraint::Min(self.bottom_pane.desired_height(area.width)),
])
.areas(area)
}
pub fn cursor_pos(&self, area: Rect) -> Option<(u16, u16)> {
let [_, bottom] = self.layout_areas(area);
self.bottom_pane.cursor_pos(bottom)
}
}
impl WidgetRef for &ChatWidget<'_> {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
let [active, bottom] = self.layout_areas(area);
(&self.bottom_pane).render(bottom, buf);
if let Some(cell) = &self.active_history_cell {
cell.render_ref(active, buf);
}
}
}
```
- Pass structured events to constructors: prefer handing `HistoryCell` the full event (e.g., `PatchApplyEndEvent`) instead of plucking out fields at the call site.
```rust
// ChatWidget handler
EventMsg::PatchApplyEnd(event) => {
self.add_to_history(HistoryCell::new_patch_apply_end(event));
}
// HistoryCell API
pub(crate) fn new_patch_apply_end(event: PatchApplyEndEvent) -> Self {
let success = event.success;
let stdout = event.stdout;
let stderr = event.stderr;
// ... build lines based on success/stdout/stderr ...
HistoryCell::PatchApplyResult { view: TextBlock::new(lines) }
}
```
- Be stingy with patch-apply output: success paths generally have non-empty `stdout`; avoid repeating content already shown earlier and limit any additional output to a small snippet.
```rust
pub(crate) fn new_patch_apply_end(event: PatchApplyEndEvent) -> Self {
let status = if event.success {
"patch applied".green()
} else {
"patch failed".red().bold()
};
let mut lines = vec![
Line::from(vec!["patch".magenta().bold(), " ".into(), status]),
"".into(),
];
// Optional, terse snippet only if helpful.
let src = if event.success {
&event.stdout // success should have useful stdout
} else if event.stderr.trim().is_empty() {
&event.stdout
} else {
&event.stderr
};
if !src.trim().is_empty() {
for l in src.lines().take(5) {
lines.push(ansi_escape_line(l).dim());
}
let remaining = src.lines().count().saturating_sub(5);
if remaining > 0 {
lines.push(Line::from(format!("... {remaining} additional lines")).dim());
}
lines.push("".into());
}
HistoryCell::PatchApplyResult { view: TextBlock::new(lines) }
}
```
**DONTs**
- Dont duplicate layout computations in multiple methods: avoid copy-pasting the same `Layout::vertical([...]).areas(area)` block in `cursor_pos()` and `render_ref()`.
```rust
// Avoid this duplication in multiple places:
let [active_cell_area, bottom_pane_area] = Layout::vertical([
Constraint::Max(self.active_history_cell.as_ref().map_or(0, |c| c.desired_height(area.width))),
Constraint::Min(self.bottom_pane.desired_height(area.width)),
]).areas(area);
// ... the same block repeated elsewhere ...
```
- Dont peel event fields at the call site just to rewrap them: it scatters knowledge of the event shape and increases churn.
```rust
// Anti-pattern: extracting fields here instead of passing the event
EventMsg::PatchApplyEnd(event) => {
self.add_to_history(HistoryCell::new_patch_apply_end(
event.stdout, event.stderr, event.success,
));
}
```
- Dont over-emit patch output or choose the wrong stream: on success, dont show `stderr`; avoid flooding the UI with long logs right after an apply-begin summary.
```rust
// Anti-patterns:
// 1) Showing stderr on success or assuming stdout might be empty on success
let src = if event.success { &event.stderr } else { &event.stdout }; // wrong
// 2) Dumping unbounded output
for l in src.lines() {
lines.push(Line::from(l.to_string())); // too verbose; no limit
}
```