fix(rooms): harden chat-room parsing and TUI state from review findings
Adversarial review of the chat-rooms feature surfaced seven confirmed issues; all fixed with regression tests: lib (DoS hardening — a malicious/MITM server could send a tiny frame with a ~4-billion element count): - room_list: bound the name/count vector loops by remaining payload. - join_room: bound the member-list loop the same way. TUI (soulseek-rs/src/models/rooms.rs, ui): - a message for a room we already left no longer resurrects its tab (route via open_index, not ensure_open). - closing a tab now clears the unread badge on the room we land on. - a room-list refresh keeps the highlight on the same room across a re-sort (track selection by name, not index). - Esc in the room list clears a lingering filter before closing, matching the title's 'Esc: clear' hint. - chat log renders one row per line so the newest message is never clipped by wrapping.
This commit is contained in:
@@ -10,7 +10,7 @@ use ratatui::{
|
||||
text::{Line, Span},
|
||||
widgets::{
|
||||
Block, Borders, Cell, HighlightSpacing, Paragraph, Row, Table,
|
||||
TableState, Wrap,
|
||||
TableState,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -181,7 +181,10 @@ fn render_messages(
|
||||
area: Rect,
|
||||
lines: &[crate::models::RoomLine],
|
||||
) {
|
||||
// Auto-scroll: keep the most recent lines that fit the height.
|
||||
// Auto-scroll: show the most recent lines. Each RoomLine renders as exactly
|
||||
// one row (no wrapping) so the tail count is exact and the newest message
|
||||
// is always visible; over-long lines are clipped at the right edge rather
|
||||
// than wrapping and pushing newer lines off the bottom.
|
||||
let height = area.height as usize;
|
||||
let start = lines.len().saturating_sub(height.max(1));
|
||||
let rendered: Vec<Line> = lines[start..]
|
||||
@@ -194,10 +197,7 @@ fn render_messages(
|
||||
None => Line::from(Span::styled(l.text.clone(), dimmed_style())),
|
||||
})
|
||||
.collect();
|
||||
frame.render_widget(
|
||||
Paragraph::new(rendered).wrap(Wrap { trim: false }),
|
||||
area,
|
||||
);
|
||||
frame.render_widget(Paragraph::new(rendered), area);
|
||||
}
|
||||
|
||||
fn render_users(frame: &mut Frame, area: Rect, users: &[String]) {
|
||||
|
||||
Reference in New Issue
Block a user