use super::cursor::{Cursor, CursorPos};
impl TextArea {
pub fn add_cursor_at(&mut self, line: usize, col: usize) {
let line = line.min(self.lines.len().saturating_sub(1));
let col = col.min(self.line_len(line));
self.cursors.add_at(CursorPos::new(line, col));
}
pub fn add_cursor_above(&mut self) {
let primary = self.cursors.primary().pos;
if primary.line > 0 {
let new_line = primary.line - 1;
let new_col = primary.col.min(self.line_len(new_line));
self.cursors.add_at(CursorPos::new(new_line, new_col));
}
}
pub fn add_cursor_below(&mut self) {
let primary = self.cursors.primary().pos;
if primary.line + 1 < self.lines.len() {
let new_line = primary.line + 1;
let new_col = primary.col.min(self.line_len(new_line));
self.cursors.add_at(CursorPos::new(new_line, new_col));
}
}
pub fn clear_secondary_cursors(&mut self) {
self.cursors.clear_secondary();
}
fn get_word_at_cursor(&self) -> String {
let pos = self.cursors.primary().pos;
let Some(line) = self.lines.get(pos.line) else {
return String::new();
};
let chars: Vec<char> = line.chars().collect();
if chars.is_empty() || pos.col >= chars.len() {
return String::new();
}
let mut start = pos.col;
let mut end = pos.col;
while start > 0 && chars[start - 1].is_alphanumeric() {
start -= 1;
}
while end < chars.len() && chars[end].is_alphanumeric() {
end += 1;
}
chars[start..end].iter().collect()
}
fn get_word_or_selection(&self) -> String {
if let Some(text) = self.get_selection() {
return text;
}
self.get_word_at_cursor()
}
fn find_next_from(&self, text: &str, from: CursorPos) -> Option<CursorPos> {
if text.is_empty() {
return None;
}
let text_lower = text.to_lowercase();
for line_idx in from.line..self.lines.len() {
let Some(line) = self.lines.get(line_idx) else {
continue;
};
let line_lower = line.to_lowercase();
let start_col = if line_idx == from.line {
from.col + 1
} else {
0
};
if start_col < line.len() {
if let Some(pos) = line_lower[start_col..].find(&text_lower) {
return Some(CursorPos::new(line_idx, start_col + pos));
}
}
}
for line_idx in 0..=from.line.min(self.lines.len().saturating_sub(1)) {
let Some(line) = self.lines.get(line_idx) else {
continue;
};
let line_lower = line.to_lowercase();
let end_col = if line_idx == from.line {
from.col + 1
} else {
line.len()
};
if let Some(pos) = line_lower[..end_col].find(&text_lower) {
let found_pos = CursorPos::new(line_idx, pos);
if !self.cursors.iter().any(|c| c.pos == found_pos) {
return Some(found_pos);
}
}
}
None
}
pub fn select_next_occurrence(&mut self) {
let text = self.get_word_or_selection();
if text.is_empty() {
return;
}
let last_pos = self
.cursors
.iter()
.map(|c| c.pos)
.max()
.unwrap_or(CursorPos::new(0, 0));
if let Some(match_pos) = self.find_next_from(&text, last_pos) {
let end_col = match_pos.col + text.len();
let new_cursor =
Cursor::with_selection(CursorPos::new(match_pos.line, end_col), match_pos);
self.cursors.add(new_cursor);
}
}
}
use super::TextArea;