use super::edit::EditOperation;
impl TextArea {
pub fn insert_char(&mut self, ch: char) {
if self.read_only {
return;
}
if self.has_selection() {
self.delete_selection();
}
if ch == '\n' {
self.insert_newline();
return;
}
if ch == '\t' {
let spaces = " ".repeat(self.tab_width);
self.insert_str(&spaces);
return;
}
let cursor_pos = self.cursors.primary().pos;
if let Some(line) = self.lines.get_mut(cursor_pos.line) {
let col = cursor_pos.col.min(line.chars().count());
let byte_col = crate::utils::text::char_to_byte_index(line, col);
line.insert(byte_col, ch);
self.push_undo(EditOperation::Insert {
line: cursor_pos.line,
col,
text: ch.to_string(),
});
self.set_primary_cursor(cursor_pos.line, col + 1);
}
}
pub fn insert_str(&mut self, s: &str) {
if self.read_only {
return;
}
if self.has_selection() {
self.delete_selection();
}
let parts: Vec<&str> = s.split('\n').collect();
if parts.len() == 1 {
let cursor_pos = self.cursors.primary().pos;
if let Some(line) = self.lines.get_mut(cursor_pos.line) {
let col = cursor_pos.col.min(line.chars().count());
let byte_col = crate::utils::text::char_to_byte_index(line, col);
line.insert_str(byte_col, s);
self.push_undo(EditOperation::Insert {
line: cursor_pos.line,
col,
text: s.to_string(),
});
self.set_primary_cursor(cursor_pos.line, col + s.chars().count());
}
} else {
for (i, part) in parts.iter().enumerate() {
let cursor_pos = self.cursors.primary().pos;
if i == 0 {
if let Some(line) = self.lines.get_mut(cursor_pos.line) {
let byte_col = crate::utils::text::char_to_byte_index(line, cursor_pos.col);
line.insert_str(byte_col, part);
}
self.set_primary_cursor(cursor_pos.line, cursor_pos.col + part.chars().count());
} else {
self.insert_newline();
let cursor_pos = self.cursors.primary().pos;
if let Some(line) = self.lines.get_mut(cursor_pos.line) {
line.insert_str(0, part);
}
self.set_primary_cursor(cursor_pos.line, part.chars().count());
}
}
}
}
fn insert_newline(&mut self) {
if self.read_only {
return;
}
if self.max_lines > 0 && self.lines.len() >= self.max_lines {
return;
}
let cursor_pos = self.cursors.primary().pos;
let (line, col) = (cursor_pos.line, cursor_pos.col);
if let Some(current) = self.lines.get_mut(line) {
let byte_col =
crate::utils::text::char_to_byte_index(current, col.min(current.chars().count()));
let rest: String = current.drain(byte_col..).collect();
self.lines.insert(line + 1, rest);
self.push_undo(EditOperation::SplitLine { line, col });
self.set_primary_cursor(line + 1, 0);
}
}
pub fn delete_char_before(&mut self) {
if self.read_only {
return;
}
if self.has_selection() {
self.delete_selection();
return;
}
let cursor_pos = self.cursors.primary().pos;
let (line, col) = (cursor_pos.line, cursor_pos.col);
if col > 0 {
if let Some(l) = self.lines.get_mut(line) {
if col <= l.chars().count() {
let byte_col = crate::utils::text::char_to_byte_index(l, col - 1);
let deleted = l.remove(byte_col);
self.push_undo(EditOperation::Delete {
line,
col: col - 1,
text: deleted.to_string(),
});
self.set_primary_cursor(line, col - 1);
}
}
} else if line > 0 {
let current = self.lines.remove(line);
if let Some(prev_line) = self.lines.get_mut(line - 1) {
let prev_len = prev_line.chars().count();
prev_line.push_str(¤t);
self.push_undo(EditOperation::MergeLines {
line: line - 1,
col: prev_len,
});
self.set_primary_cursor(line - 1, prev_len);
}
}
}
pub fn delete_char_at(&mut self) {
if self.read_only {
return;
}
if self.has_selection() {
self.delete_selection();
return;
}
let cursor_pos = self.cursors.primary().pos;
let (line, col) = (cursor_pos.line, cursor_pos.col);
let can_delete_in_line = self
.lines
.get(line)
.map(|l| col < l.chars().count())
.unwrap_or(false);
if can_delete_in_line {
if let Some(l) = self.lines.get_mut(line) {
let byte_col = crate::utils::text::char_to_byte_index(l, col);
let deleted = l.remove(byte_col);
self.push_undo(EditOperation::Delete {
line,
col,
text: deleted.to_string(),
});
}
} else if line + 1 < self.lines.len() {
let next = self.lines.remove(line + 1);
if let Some(current_line) = self.lines.get_mut(line) {
current_line.push_str(&next);
self.push_undo(EditOperation::MergeLines { line, col });
}
}
}
pub fn delete_line(&mut self) {
if self.read_only || self.lines.len() <= 1 {
return;
}
let cursor_pos = self.cursors.primary().pos;
let line = cursor_pos.line;
let content = self.lines.remove(line);
self.push_undo(EditOperation::DeleteLine { line, content });
let new_line = line.min(self.lines.len().saturating_sub(1));
self.set_primary_cursor(new_line, 0);
}
pub fn duplicate_line(&mut self) {
if self.read_only {
return;
}
let cursor_pos = self.cursors.primary().pos;
let line = cursor_pos.line;
if let Some(content) = self.lines.get(line).cloned() {
self.lines.insert(line + 1, content.clone());
self.push_undo(EditOperation::InsertLine {
line: line + 1,
content,
});
self.set_primary_cursor(line + 1, cursor_pos.col);
}
}
}
use super::TextArea;