fix(tui): defensive mouse-report sanitizer and move provider-wait logging off render path
Strip SGR mouse coordinate tails even when mouse capture is disabled, covering orphaned terminal reporting state after crashes or focus races (#3063/#3067). Move provider-wait incident logging from footer render to the main tick loop so stall diagnostics do not fire on every redraw (#3095 harvest note). Co-authored-by: Hunter Bown <101357273+Hmbown@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3821,9 +3821,6 @@ impl App {
|
||||
}
|
||||
|
||||
fn strip_raw_mouse_reports_from_input(&mut self) {
|
||||
if !self.use_mouse_capture {
|
||||
return;
|
||||
}
|
||||
if let Some((input, cursor_position)) =
|
||||
strip_raw_mouse_report_runs(&self.input, self.cursor_position)
|
||||
{
|
||||
@@ -5653,12 +5650,34 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_keeps_mouse_like_text_when_mouse_capture_is_disabled() {
|
||||
fn composer_strips_raw_sgr_mouse_report_when_mouse_capture_is_disabled() {
|
||||
let mut app = App::new(test_options(false), &Config::default());
|
||||
|
||||
app.insert_str("[<35;44;18M");
|
||||
|
||||
assert_eq!(app.input, "[<35;44;18M");
|
||||
assert_eq!(app.input, "");
|
||||
assert_eq!(app.cursor_position, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_strips_tail_only_mouse_report_burst_when_mouse_capture_is_disabled() {
|
||||
let mut app = App::new(test_options(false), &Config::default());
|
||||
app.insert_str("draft ");
|
||||
|
||||
app.insert_str(";76;20M35;74;22M35;73;23M");
|
||||
|
||||
assert_eq!(app.input, "draft ");
|
||||
assert_eq!(app.cursor_position, "draft ".chars().count());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_keeps_coordinate_like_text_when_mouse_capture_is_disabled() {
|
||||
let mut app = App::new(test_options(false), &Config::default());
|
||||
|
||||
app.insert_str("Size 12;34M");
|
||||
|
||||
assert_eq!(app.input, "Size 12;34M");
|
||||
assert_eq!(app.cursor_position, "Size 12;34M".chars().count());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -93,7 +93,6 @@ pub(crate) fn render_footer(f: &mut Frame, area: Rect, app: &mut App) {
|
||||
if let Some(reason) = stall_reason(app) {
|
||||
label = format!("{label} ({reason})");
|
||||
}
|
||||
maybe_log_provider_wait_incident(app);
|
||||
props.state_label = label;
|
||||
props.state_color = palette::DEEPSEEK_SKY;
|
||||
|
||||
|
||||
@@ -2759,6 +2759,7 @@ async fn run_event_loop(
|
||||
// window. Triggers a redraw if the prompt was visible.
|
||||
app.tick_quit_armed();
|
||||
app.tick_receipt();
|
||||
crate::tui::footer_ui::maybe_log_provider_wait_incident(app);
|
||||
// While the user is drag-selecting past the transcript edge, advance
|
||||
// the viewport on a fixed cadence and extend the selection head so a
|
||||
// long passage can be selected in one drag (#1163).
|
||||
|
||||
Reference in New Issue
Block a user