use super::{App, CopyOption, Popup, code_blocks};
impl App {
pub(crate) fn copy_text(&mut self, text: &str) {
let msg = crate::input::copy_to_clipboard(&mut self.clipboard, text);
if !msg.is_empty() {
self.status = msg;
}
}
pub(crate) fn copy_message(&mut self, idx: usize) {
let text = match self.messages.get(idx) {
Some(m) if m.role == "assistant" => Some(crate::markdown::to_plain(&m.content)),
Some(m) => Some(m.content.clone()),
None if idx == self.messages.len() => self.active_streaming_text().map(str::to_string),
None => None,
};
if let Some(t) = text {
self.copy_text(&t);
}
}
pub(super) fn open_copy_menu(&mut self) {
let opts = {
let Some(msg) = self.messages.iter().rev().find(|m| m.role == "assistant") else {
self.status = "no response to copy".into();
return;
};
let mut opts = vec![CopyOption {
label: "Entire response".into(),
text: crate::markdown::to_plain(&msg.content),
}];
for (i, (lang, code)) in code_blocks(&msg.content).into_iter().enumerate() {
let label = match lang {
Some(l) => format!("Code block {} ({l})", i + 1),
None => format!("Code block {}", i + 1),
};
opts.push(CopyOption { label, text: code });
}
opts
};
self.copy_options = opts;
self.copy_selected = 0;
self.popup = Popup::Copy;
}
pub(crate) fn confirm_copy(&mut self) {
if let Some(text) = self
.copy_options
.get(self.copy_selected)
.map(|o| o.text.clone())
{
self.copy_text(&text);
}
self.popup = Popup::None;
}
pub(crate) fn move_copy_selection(&mut self, delta: i32) {
self.copy_selected =
super::clamp_cursor(self.copy_selected, self.copy_options.len(), delta);
}
}