use crate::app::{App, Focus};
use crate::config::ClipboardBackend;
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use super::backend::copy_to_clipboard;
pub fn handle_clipboard_key(app: &mut App, key: KeyEvent, backend: ClipboardBackend) -> bool {
if key.code == KeyCode::Char('y') && key.modifiers.contains(KeyModifiers::CONTROL) {
return copy_focused_content(app, backend);
}
false
}
pub fn handle_yank_key(app: &mut App, backend: ClipboardBackend) -> bool {
copy_focused_content(app, backend)
}
fn copy_focused_content(app: &mut App, backend: ClipboardBackend) -> bool {
match app.focus {
Focus::InputField => copy_query(app, backend),
Focus::ResultsPane => copy_result(app, backend),
}
}
fn copy_query(app: &mut App, backend: ClipboardBackend) -> bool {
let query = app.query();
if query.is_empty() {
log::debug!("Clipboard: query is empty, nothing to copy");
return false;
}
if copy_to_clipboard(query, backend).is_ok() {
app.notification.show("Copied query!");
true
} else {
false
}
}
fn copy_result(app: &mut App, backend: ClipboardBackend) -> bool {
let query_state = match &app.query {
Some(q) => q,
None => {
log::debug!("Clipboard: no query state, nothing to copy");
return false;
}
};
let full_result = match &query_state.last_successful_result_unformatted {
Some(text) => text.as_ref().to_string(),
None => {
log::debug!("Clipboard: no result available to copy");
return false;
}
};
if full_result.is_empty() {
log::debug!("Clipboard: result is empty, nothing to copy");
return false;
}
let (result, notification) = if app.results_cursor.is_visual_mode() {
let (start, end) = app.results_cursor.selection_range();
let lines: Vec<&str> = full_result.lines().collect();
let start_idx = start as usize;
let end_idx = (end as usize).min(lines.len().saturating_sub(1));
if start_idx < lines.len() {
let selected: String = lines[start_idx..=end_idx].join("\n");
let line_count = end_idx - start_idx + 1;
let notification = if line_count == 1 {
"Copied 1 line!".to_string()
} else {
format!("Copied {} lines!", line_count)
};
(selected, notification)
} else {
return false;
}
} else {
(full_result, "Copied result!".to_string())
};
if result.is_empty() {
return false;
}
if copy_to_clipboard(&result, backend).is_ok() {
app.notification.show(¬ification);
true
} else {
false
}
}
#[cfg(test)]
pub fn strip_ansi_codes(text: &str) -> String {
let mut result = String::with_capacity(text.len());
let mut chars = text.chars().peekable();
while let Some(c) = chars.next() {
if c == '\x1b' {
match chars.peek() {
Some(&'[') => {
chars.next(); while let Some(&next) = chars.peek() {
chars.next();
if next.is_ascii_alphabetic() {
break;
}
}
}
Some(&']') => {
chars.next(); while let Some(&next) = chars.peek() {
if next == '\x07' {
chars.next();
break;
}
if next == '\x1b' {
chars.next();
if chars.peek() == Some(&'\\') {
chars.next();
}
break;
}
chars.next();
}
}
Some(_) => {
chars.next();
}
None => {
}
}
} else {
result.push(c);
}
}
result
}
#[cfg(test)]
#[path = "clipboard_events_tests.rs"]
mod clipboard_events_tests;