diff --git a/crates/codegen/kigi-tools/src/computer/local/cgroup.rs b/crates/codegen/kigi-tools/src/computer/local/cgroup.rs index 6afd6f1..32040ef 100644 --- a/crates/codegen/kigi-tools/src/computer/local/cgroup.rs +++ b/crates/codegen/kigi-tools/src/computer/local/cgroup.rs @@ -148,7 +148,6 @@ mod linux { } let err = std::io::Error::last_os_error(); match err.kind() { - // The fd is non-blocking: the queue is empty. std::io::ErrorKind::WouldBlock => break, std::io::ErrorKind::Interrupted => continue, _ => return Err(err), diff --git a/crates/codegen/kigi-tui/src/app/event_loop.rs b/crates/codegen/kigi-tui/src/app/event_loop.rs index 28b7144..770cb19 100644 --- a/crates/codegen/kigi-tui/src/app/event_loop.rs +++ b/crates/codegen/kigi-tui/src/app/event_loop.rs @@ -2333,11 +2333,7 @@ async fn drain_and_process( } // On terminals without bracketed paste, try to capture more events - // that may still be in transit from the input reader thread. A batch - // that already holds a key burst skips the short detection window: - // its 2 ms budget is below one Windows scheduler quantum, so a - // mid-paste gap would end collection before it starts and the paste - // tail would arrive as a separate fragment. + // that may still be in transit from the input reader thread. if should_extend_for_paste(&raw_events) && (is_paste_burst(&raw_events) || detect_paste(&mut raw_events, input_rx).await) { @@ -2542,18 +2538,13 @@ async fn drain_and_process( const PASTE_DETECT_TIMEOUT: Duration = Duration::from_millis(2); /// Timeout for subsequent rounds once paste has been detected. Must exceed -/// one Windows scheduler quantum (~15.6 ms): ConPTY delivers a paste as a -/// per-character key burst, and a mid-burst gap of one quantum is routine. -/// A smaller window ends collection mid-paste; the tail then arrives as a -/// second synthetic paste, whose content can never match the paste chip, so -/// repaste-to-expand inserts a duplicate instead of expanding. +/// one Windows scheduler quantum (~15.6 ms), or a routine mid-burst gap +/// splits the paste and repaste-to-expand duplicates instead of expanding. const PASTE_CONTINUE_TIMEOUT: Duration = Duration::from_millis(25); -/// Safety cap on events accumulated in one extension pass. On the -/// no-bracketed-paste path a paste is one key event per character, so the -/// cap must exceed any real paste (~200 KB of text); hitting it splits the -/// paste with the same duplicate-on-repaste effect as a timeout split. The -/// idle timeout above, not this cap, is the normal terminator. +/// Safety cap on events accumulated in one extension pass. Pastes arrive +/// one key event per character here, so the cap must exceed any real paste; +/// hitting it splits the paste like a timeout miss would. const PASTE_EXTEND_MAX_EVENTS: usize = 200_000; /// Returns `true` when the batch contains pasteable key events but no @@ -2564,12 +2555,11 @@ fn should_extend_for_paste(events: &[Event]) -> bool { } /// Minimum pasteable key events already in one batch to classify it as a -/// paste burst in progress. Human typing and key auto-repeat deliver one -/// or two events per batch; only a paste chunk lands more at once. +/// paste burst; typing and auto-repeat deliver only a couple per batch. const PASTE_BURST_BATCH_EVENTS: usize = 8; -/// True when the batch alone proves a paste is in progress, without -/// waiting on [`PASTE_DETECT_TIMEOUT`]. +/// True when the batch alone proves a paste is in progress, so collection +/// can start without the [`PASTE_DETECT_TIMEOUT`] round-trip. fn is_paste_burst(events: &[Event]) -> bool { events.iter().filter(|e| is_pasteable_key_event(e)).count() >= PASTE_BURST_BATCH_EVENTS } @@ -3188,11 +3178,9 @@ mod tests { #[test] fn typing_and_release_storms_are_not_a_paste_burst() { - // A short typed run stays below the burst threshold. let typed = vec![press(KeyCode::Char('h')), press(KeyCode::Char('i'))]; assert!(!is_paste_burst(&typed)); - // Release events carry no content and must not count toward it. let releases: Vec = "releases only!" .chars() .map(|c| release(KeyCode::Char(c))) @@ -3200,10 +3188,8 @@ mod tests { assert!(!is_paste_burst(&releases)); } - /// A key-burst paste whose tail trickles in with sub-window gaps must - /// reassemble into ONE synthetic paste. A split here is what made - /// repaste-to-expand insert a duplicate chip on Windows: the fragment - /// could never byte-equal the chip content. + /// A burst tail trickling in with one-quantum gaps must reassemble into + /// ONE paste — a split is what duplicated chips on Windows. #[tokio::test(start_paused = true)] async fn burst_tail_with_scheduler_gaps_reassembles_into_one_paste() { let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); @@ -3213,8 +3199,6 @@ mod tests { let mut batch: Vec = head.chars().map(char_or_enter).collect(); assert!(is_paste_burst(&batch), "head chunk must classify as burst"); - // Trickle the tail with 15 ms gaps — one Windows scheduler quantum, - // larger than the old 10 ms window, smaller than the current one. tokio::spawn(async move { for c in tail.chars() { tokio::time::sleep(Duration::from_millis(15)).await;