use cosmic_text::Action;
use cosmic_text::BorrowedWithFontSystem;
use cosmic_text::Edit;
use cosmic_text::Editor;
use cosmic_text::Motion;
use cosmic_text::Selection;
use crate::TextInputFilter;
use crate::clipboard::ClipboardRead;
use crate::edit::apply_action;
use crate::edit::apply_motion;
use crate::edit::buffer_len;
use crate::edit::cursor_at_line_end;
#[derive(Debug)]
pub enum TextInputAction {
Submit,
Copy,
Cut,
Paste,
PasteDeferred(ClipboardRead),
Edit(TextInputEdit),
}
#[derive(Debug)]
pub enum TextInputEdit {
Motion(Motion, bool),
Escape,
Insert(char, bool),
Enter,
Backspace,
Delete,
Indent,
Unindent,
Click {
x: i32,
y: i32,
},
DoubleClick {
x: i32,
y: i32,
},
TripleClick {
x: i32,
y: i32,
},
Drag {
x: i32,
y: i32,
},
Scroll {
lines: i32,
},
Paste(String),
Undo,
Redo,
SelectAll,
}
pub fn apply_text_input_edit(
edit: TextInputEdit,
editor: &mut BorrowedWithFontSystem<'_, Editor<'static>>,
changes: &mut cosmic_undo_2::Commands<cosmic_text::Change>,
max_chars: Option<usize>,
filter_mode: &Option<TextInputFilter>,
) {
editor.start_change();
match edit {
TextInputEdit::Motion(motion, with_select) => {
apply_motion(editor, with_select, motion);
}
TextInputEdit::Escape => {
editor.action(Action::Escape);
}
TextInputEdit::Insert(ch, overwrite) => {
if editor.selection() != Selection::None {
editor.action(Action::Insert(ch));
} else if overwrite && !cursor_at_line_end(editor) {
editor.action(Action::Delete);
editor.action(Action::Insert(ch));
} else if max_chars.is_none_or(|max_chars| editor.with_buffer(buffer_len) < max_chars) {
editor.action(Action::Insert(ch));
}
}
TextInputEdit::Backspace => {
if editor.delete_selection() {
editor.set_redraw(true);
} else {
editor.action(Action::Backspace);
}
}
TextInputEdit::Delete => {
if editor.delete_selection() {
editor.set_redraw(true);
} else {
editor.action(Action::Delete);
}
}
TextInputEdit::Indent => {
editor.action(Action::Indent);
}
TextInputEdit::Unindent => {
editor.action(Action::Unindent);
}
TextInputEdit::Click { x, y } => {
editor.action(Action::Click { x, y });
}
TextInputEdit::DoubleClick { x, y } => {
editor.action(Action::DoubleClick { x, y });
}
TextInputEdit::TripleClick { x, y } => {
editor.action(Action::DoubleClick { x, y });
}
TextInputEdit::Drag { x, y } => {
editor.action(Action::Drag { x, y });
}
TextInputEdit::Scroll { lines } => {
editor.action(Action::Scroll { lines });
}
TextInputEdit::Paste(text) => {
if max_chars.is_none_or(|max| editor.with_buffer(buffer_len) + text.len() <= max) {
editor.insert_string(&text, None);
}
}
TextInputEdit::Undo => {
for action in changes.undo() {
apply_action(editor, action);
editor.set_redraw(true);
}
}
TextInputEdit::Redo => {
for action in changes.redo() {
apply_action(editor, action);
editor.set_redraw(true);
}
}
TextInputEdit::SelectAll => {
editor.action(Action::Motion(Motion::BufferStart));
let cursor = editor.cursor();
editor.set_selection(Selection::Normal(cursor));
editor.action(Action::Motion(Motion::BufferEnd));
}
TextInputEdit::Enter => {
editor.action(Action::Enter);
}
}
let Some(mut change) = editor.finish_change() else {
return;
};
if change.items.is_empty() {
return;
}
if let Some(filter_mode) = filter_mode {
let text = editor.with_buffer(crate::get_text);
if !filter_mode.is_match(&text) {
change.reverse();
editor.apply_change(&change);
return;
}
}
changes.push(change);
editor.set_redraw(true);
}