use teksilo_core::widget::EventContext;
use teksilo_platform::clipboard::ClipboardHandle;
use teksilo_text::text_document::{MoveMode, TextCursor};
use super::state::CodeEditorState;
fn target_text(st: &CodeEditorState) -> Option<(String, bool)> {
if st.cursor.has_selection() {
st.cursor.selected_text().ok().map(|t| (t, false))
} else {
st.document
.snapshot_block_at_position_without_highlights(st.cursor.position())
.map(|b| (b.text, true))
}
}
pub(super) fn copy(st: &CodeEditorState, ctx: &EventContext) {
let Some((text, _)) = target_text(st) else {
return;
};
if let Some(cb) = ctx.app_state::<ClipboardHandle>() {
let _ = cb.set_text(&text);
}
}
pub(super) fn cut(st: &mut CodeEditorState, ctx: &EventContext) {
let Some((text, is_line)) = target_text(st) else {
return;
};
if let Some(cb) = ctx.app_state::<ClipboardHandle>() {
let _ = cb.set_text(&text);
}
if is_line {
st.clear_extra_carets();
delete_line(st);
} else {
let _ = st.cursor.remove_selected_text();
}
st.merge_collided_carets();
}
pub(super) fn delete_line(st: &mut CodeEditorState) {
let pos = st.cursor.position();
let Some(block) = st
.document
.snapshot_block_at_position_without_highlights(pos)
else {
return;
};
let start = block.position;
let end = start + block.length;
let doc_end = st.document.character_count();
let (from, to) = if end < doc_end {
(start, end + 1) } else if start > 0 {
(start - 1, end) } else {
(start, end) };
st.cursor.set_position(from, MoveMode::MoveAnchor);
st.cursor.set_position(to, MoveMode::KeepAnchor);
let _ = st.cursor.remove_selected_text();
}
pub(super) fn paste(st: &mut CodeEditorState, ctx: &EventContext) {
let Some(cb) = ctx.app_state::<ClipboardHandle>() else {
return;
};
let Ok(text) = cb.get_text() else {
return;
};
if text.is_empty() {
return;
}
let normalized = text.replace("\r\n", "\n").replace('\r', "\n");
st.clear_extra_carets();
insert_multiline(&st.cursor, &normalized);
}
pub(super) fn insert_multiline(cursor: &TextCursor, text: &str) {
cursor.begin_edit_block();
for (i, line) in text.split('\n').enumerate() {
if i > 0 {
let _ = cursor.insert_block();
}
if !line.is_empty() {
let _ = cursor.insert_text(line);
}
}
cursor.end_edit_block();
}