Skip to content

Commit 6b11679

Browse files
committed
fix clippy warning and readme rendering
1 parent 7e4c3b4 commit 6b11679

File tree

3 files changed

+84
-65
lines changed

3 files changed

+84
-65
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

assets/eventage-replay.png

256 KB
Loading

crates/example-coding-agent/src/tui.rs

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ struct AppState {
7575
/// When true, auto-scroll to bottom on new content.
7676
auto_scroll: bool,
7777
/// When true, the next stream chunk must start on a fresh agent line
78-
/// (set after a TOOL_RESULT so text doesn't concatenate onto the result).
78+
/// (set after a `TOOL_RESULT` so text doesn't concatenate onto the result).
7979
pending_stream_newline: bool,
80-
/// True between AGENT_CYCLE_START and AGENT_CYCLE_END.
80+
/// True between `AGENT_CYCLE_START` and `AGENT_CYCLE_END`.
8181
/// Stream chunks outside a cycle are dropped (late-arriving bus events).
8282
in_cycle: bool,
8383
}
@@ -236,6 +236,7 @@ fn word_wrap_rows(text: &str, width: usize) -> usize {
236236
/// The wrap decision for each word is made **before** checking the cursor so
237237
/// that a cursor at the start of a wrapped word lands on the new row, not the
238238
/// old one.
239+
#[allow(clippy::cast_possible_truncation)]
239240
fn word_wrap_cursor(text: &str, cursor_char_abs: usize, width: usize) -> (u16, u16) {
240241
if width == 0 {
241242
return (0, 0);
@@ -293,51 +294,9 @@ fn word_wrap_cursor(text: &str, cursor_char_abs: usize, width: usize) -> (u16, u
293294
(row, col as u16)
294295
}
295296

296-
#[cfg(test)]
297-
mod wrap_tests {
298-
use super::*;
299-
300-
// Prefix used by the input bar.
301-
const P: &str = " > ";
302-
303-
#[test]
304-
fn empty_input_cursor_after_prefix() {
305-
// " > " — cursor at position 3 (just after the prefix), width=80
306-
assert_eq!(word_wrap_cursor(P, 3, 80), (0, 3));
307-
assert_eq!(word_wrap_rows(P, 80), 1);
308-
}
309-
310-
#[test]
311-
fn one_char_cursor_at_end() {
312-
// " > a" — cursor at 4
313-
assert_eq!(word_wrap_cursor(" > a", 4, 80), (0, 4));
314-
assert_eq!(word_wrap_rows(" > a", 80), 1);
315-
}
316-
317-
#[test]
318-
fn word_wraps_to_new_row() {
319-
// " > hello world" at width=10: "hello" fits row 0, "world" wraps to row 1.
320-
// Cursor at 9 ('w') should be (1, 0) after the wrap decision.
321-
assert_eq!(word_wrap_cursor(" > hello world", 9, 10), (1, 0));
322-
assert_eq!(word_wrap_rows(" > hello world", 10), 2);
323-
}
324-
325-
#[test]
326-
fn cursor_at_very_start() {
327-
assert_eq!(word_wrap_cursor("hello", 0, 80), (0, 0));
328-
}
329-
330-
#[test]
331-
fn hard_wrap_long_word() {
332-
// "aaaaaaaaaaa" (11 a's) at width=10: spills onto row 2
333-
assert_eq!(word_wrap_rows("aaaaaaaaaaa", 10), 2);
334-
// Cursor at position 10 (start of row 2)
335-
assert_eq!(word_wrap_cursor("aaaaaaaaaaa", 10, 10), (1, 0));
336-
}
337-
}
338-
339297
// ── Rendering ─────────────────────────────────────────────────────────────────
340298

299+
#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
341300
fn render(frame: &mut Frame, state: &AppState) {
342301
let area = frame.area();
343302
let prefix = " > ";
@@ -354,8 +313,8 @@ fn render(frame: &mut Frame, state: &AppState) {
354313
let chunks = Layout::default()
355314
.direction(Direction::Vertical)
356315
.constraints([
357-
Constraint::Length(2), // status bar
358-
Constraint::Min(0), // conversation
316+
Constraint::Length(2), // status bar
317+
Constraint::Min(0), // conversation
359318
Constraint::Length(input_height), // input bar (dynamic)
360319
])
361320
.split(area);
@@ -421,12 +380,13 @@ fn render(frame: &mut Frame, state: &AppState) {
421380

422381
// Scroll indicator at the bottom of the log area
423382
if effective_scroll > 0 {
424-
let indicator_text = format!(
425-
" ▼ {} more below [↓/PgDn to scroll, G to jump to bottom] ",
426-
effective_scroll
383+
let indicator_text =
384+
format!(" ▼ {effective_scroll} more below [↓/PgDn to scroll, G to jump to bottom] ");
385+
let indicator = Paragraph::new(indicator_text).style(
386+
Style::default()
387+
.fg(Color::DarkGray)
388+
.add_modifier(Modifier::DIM),
427389
);
428-
let indicator = Paragraph::new(indicator_text)
429-
.style(Style::default().fg(Color::DarkGray).add_modifier(Modifier::DIM));
430390
let indicator_area = Rect {
431391
x: log_area.x,
432392
y: log_area.y + log_area.height.saturating_sub(1),
@@ -559,12 +519,18 @@ fn centred_rect_fixed(width: u16, height: u16, area: Rect) -> Rect {
559519
let h = height.min(area.height);
560520
let x = area.x + (area.width.saturating_sub(w)) / 2;
561521
let y = area.y + (area.height.saturating_sub(h)) / 2;
562-
Rect { x, y, width: w, height: h }
522+
Rect {
523+
x,
524+
y,
525+
width: w,
526+
height: h,
527+
}
563528
}
564529

565530
// ── Bus event handling ────────────────────────────────────────────────────────
566531

567-
fn handle_bus_event(state: &mut AppState, event: Event) {
532+
#[allow(clippy::too_many_lines)]
533+
fn handle_bus_event(state: &mut AppState, event: &Event) {
568534
match event.kind.as_str() {
569535
k if k == core_kinds::USER_MESSAGE => {
570536
let text = event.payload["text"].as_str().unwrap_or("").to_string();
@@ -614,7 +580,9 @@ fn handle_bus_event(state: &mut AppState, event: Event) {
614580
state.push(Line::from(""));
615581
state.push(Line::from(vec![Span::styled(
616582
" agent ",
617-
Style::default().fg(Color::Green).add_modifier(Modifier::BOLD),
583+
Style::default()
584+
.fg(Color::Green)
585+
.add_modifier(Modifier::BOLD),
618586
)]));
619587
}
620588

@@ -723,21 +691,27 @@ fn handle_bus_event(state: &mut AppState, event: Event) {
723691
let args_preview = event
724692
.payload
725693
.get("args")
726-
.map(|v| v.to_string())
694+
.map(ToString::to_string)
727695
.unwrap_or_default();
728696
// Push a visible pause line so the conversation log doesn't look
729697
// abruptly truncated — the stream stopped here on purpose.
730698
state.push(Line::from(vec![Span::styled(
731699
format!(" ⏸ approval required for {tool} (Y/N)"),
732-
Style::default().fg(Color::Yellow).add_modifier(Modifier::DIM),
700+
Style::default()
701+
.fg(Color::Yellow)
702+
.add_modifier(Modifier::DIM),
733703
)]));
734704
state.mode = Mode::AwaitingApproval { tool, args_preview };
735705
}
736706

737707
k if k == CODING_APPROVAL_GRANTED || k == CODING_APPROVAL_DENIED => {
738708
let granted = k == CODING_APPROVAL_GRANTED;
739709
state.push(Line::from(vec![Span::styled(
740-
if granted { " ▶ approved" } else { " ✗ denied" },
710+
if granted {
711+
" ▶ approved"
712+
} else {
713+
" ✗ denied"
714+
},
741715
Style::default()
742716
.fg(if granted { Color::Green } else { Color::Red })
743717
.add_modifier(Modifier::DIM),
@@ -753,7 +727,7 @@ fn handle_bus_event(state: &mut AppState, event: Event) {
753727
let deleted = event.payload["deleted_files"].as_u64().unwrap_or(0);
754728
if changed + new + deleted > 0 {
755729
state.push(Line::from(vec![Span::styled(
756-
format!(" ∆ {} changed, {} new, {} deleted", changed, new, deleted),
730+
format!(" ∆ {changed} changed, {new} new, {deleted} deleted"),
757731
Style::default().fg(Color::Blue),
758732
)]));
759733
}
@@ -790,7 +764,9 @@ fn handle_bus_event(state: &mut AppState, event: Event) {
790764
state.push(Line::from(vec![
791765
Span::styled(
792766
format!(" ✓ sub-agent #{id_short} "),
793-
Style::default().fg(Color::Green).add_modifier(Modifier::BOLD),
767+
Style::default()
768+
.fg(Color::Green)
769+
.add_modifier(Modifier::BOLD),
794770
),
795771
Span::styled(preview, Style::default().fg(Color::Green)),
796772
]));
@@ -831,7 +807,7 @@ async fn handle_key(
831807
// ── Global shortcuts ──────────────────────────────────────────────────────
832808
if key.modifiers.contains(KeyModifiers::CONTROL) {
833809
match key.code {
834-
KeyCode::Char('c') | KeyCode::Char('q') => {
810+
KeyCode::Char('c' | 'q') => {
835811
return KeyAction::Quit;
836812
}
837813
KeyCode::Char('x') => {
@@ -900,14 +876,14 @@ async fn handle_key(
900876

901877
// ── AwaitingApproval: y/n + scroll ────────────────────────────────────
902878
Mode::AwaitingApproval { .. } => match key.code {
903-
KeyCode::Char('y') | KeyCode::Char('Y') => {
879+
KeyCode::Char('y' | 'Y') => {
904880
debug!("user granted tool approval");
905881
let _ = bus
906882
.publish(Event::new(CODING_APPROVAL_GRANTED, json!({})))
907883
.await;
908884
state.mode = Mode::Working;
909885
}
910-
KeyCode::Char('n') | KeyCode::Char('N') => {
886+
KeyCode::Char('n' | 'N') => {
911887
debug!("user denied tool approval");
912888
let _ = bus
913889
.publish(Event::new(CODING_APPROVAL_DENIED, json!({})))
@@ -994,7 +970,7 @@ pub async fn run_tui(
994970
maybe_event = bus_rx.recv() => {
995971
match maybe_event {
996972
Some(event) => {
997-
handle_bus_event(&mut state, event);
973+
handle_bus_event(&mut state, &event);
998974
needs_redraw = true;
999975
}
1000976
None => break,
@@ -1032,3 +1008,46 @@ pub async fn run_tui(
10321008

10331009
result
10341010
}
1011+
1012+
#[cfg(test)]
1013+
mod wrap_tests {
1014+
use super::*;
1015+
1016+
// Prefix used by the input bar.
1017+
const P: &str = " > ";
1018+
1019+
#[test]
1020+
fn empty_input_cursor_after_prefix() {
1021+
// " > " — cursor at position 3 (just after the prefix), width=80
1022+
assert_eq!(word_wrap_cursor(P, 3, 80), (0, 3));
1023+
assert_eq!(word_wrap_rows(P, 80), 1);
1024+
}
1025+
1026+
#[test]
1027+
fn one_char_cursor_at_end() {
1028+
// " > a" — cursor at 4
1029+
assert_eq!(word_wrap_cursor(" > a", 4, 80), (0, 4));
1030+
assert_eq!(word_wrap_rows(" > a", 80), 1);
1031+
}
1032+
1033+
#[test]
1034+
fn word_wraps_to_new_row() {
1035+
// " > hello world" at width=10: "hello" fits row 0, "world" wraps to row 1.
1036+
// Cursor at 9 ('w') should be (1, 0) after the wrap decision.
1037+
assert_eq!(word_wrap_cursor(" > hello world", 9, 10), (1, 0));
1038+
assert_eq!(word_wrap_rows(" > hello world", 10), 2);
1039+
}
1040+
1041+
#[test]
1042+
fn cursor_at_very_start() {
1043+
assert_eq!(word_wrap_cursor("hello", 0, 80), (0, 0));
1044+
}
1045+
1046+
#[test]
1047+
fn hard_wrap_long_word() {
1048+
// "aaaaaaaaaaa" (11 a's) at width=10: spills onto row 2
1049+
assert_eq!(word_wrap_rows("aaaaaaaaaaa", 10), 2);
1050+
// Cursor at position 10 (start of row 2)
1051+
assert_eq!(word_wrap_cursor("aaaaaaaaaaa", 10, 10), (1, 0));
1052+
}
1053+
}

0 commit comments

Comments
 (0)