Skip to main content

codetether_agent/tui/app/input/
paste.rs

1//! Paste event handling for the TUI.
2//!
3//! Normalises line endings and dispatches pasted text to the
4//! correct input buffer based on the active view mode.
5//!
6//! # Examples
7//!
8//! ```ignore
9//! handle_paste(&mut app, "multi\nline").await;
10//! ```
11
12use crate::tui::app::state::App;
13use crate::tui::app::symbols::{refresh_symbol_search, symbol_search_active};
14use crate::tui::models::{InputMode, ViewMode};
15
16/// Handle pasted text from the terminal.
17///
18/// Normalises line endings, then dispatches to symbol search,
19/// bus filter, model filter, sessions filter, or chat input.
20///
21/// # Examples
22///
23/// ```ignore
24/// handle_paste(&mut app, "pasted\ntext").await;
25/// ```
26pub async fn handle_paste(app: &mut App, text: &str) {
27    let normalized = text.replace("\r\n", "\n").replace('\r', "\n");
28
29    if symbol_search_active(app) {
30        paste_chars_no_newlines(&normalized, |ch| app.state.symbol_search.handle_char(ch));
31        refresh_symbol_search(app).await;
32        return;
33    }
34    if app.state.view_mode == ViewMode::Bus && app.state.bus_log.filter_input_mode {
35        paste_chars_no_newlines(&normalized, |ch| app.state.bus_log.push_filter_char(ch));
36        app.state.status = format!("Protocol filter: {}", app.state.bus_log.filter);
37        return;
38    }
39    if app.state.view_mode == ViewMode::Model {
40        paste_chars_no_newlines(&normalized, |ch| app.state.model_filter_push(ch));
41        return;
42    }
43    if app.state.view_mode == ViewMode::Sessions {
44        paste_chars_no_newlines(&normalized, |ch| app.state.session_filter_push(ch));
45        return;
46    }
47    if app.state.view_mode == ViewMode::Chat {
48        paste_into_chat(app, &normalized);
49    }
50}
51
52/// Iterate non-newline characters and feed them to `f`.
53fn paste_chars_no_newlines(text: &str, mut f: impl FnMut(char)) {
54    for ch in text.chars().filter(|ch| *ch != '\n') {
55        f(ch);
56    }
57}
58
59/// Insert pasted text into the chat input buffer.
60fn paste_into_chat(app: &mut App, normalized: &str) {
61    app.state.input_mode = if app.state.input.is_empty() && normalized.starts_with('/') {
62        InputMode::Command
63    } else if app.state.input.starts_with('/') {
64        InputMode::Command
65    } else {
66        InputMode::Editing
67    };
68    app.state.insert_text(normalized);
69    let line_count = normalized.lines().count();
70    app.state.status = if line_count > 1 {
71        format!("Pasted {line_count} lines into input")
72    } else {
73        "Pasted into input".to_string()
74    };
75}