use typ_buffer::{Position, SearchQuery, Selection};
use typ_core::PanelEvent;
use crate::EditorPanel;
impl EditorPanel {
fn select_word_under_caret(&mut self) -> bool {
let primary = self.selections.primary();
if !primary.is_empty() {
return false;
}
let cursor = primary.head;
let word = self
.buffer
.with_line_str(cursor.line, |line| typ_buffer::word_at(line, cursor.col));
let Some((start, end)) = word else {
return false;
};
self.selections.set_single(Selection {
anchor: Position {
line: cursor.line,
col: start,
},
head: Position {
line: cursor.line,
col: end,
},
});
self.goal_col = None;
true
}
fn occurrence_needle(&self) -> Option<String> {
let primary = self.selections.primary();
if primary.is_empty() {
return None;
}
let (start, end) = primary.range();
Some(self.buffer.text_in_range(start, end))
}
fn occurrence_query(needle: String) -> SearchQuery {
SearchQuery::new(needle, true)
}
pub(crate) fn select_next_occurrence(&mut self) -> Option<Vec<PanelEvent>> {
if self.select_word_under_caret() {
return Some(vec![PanelEvent::NeedsRedraw]);
}
let Some(needle) = self.occurrence_needle() else {
return Some(Vec::new());
};
let from = self.selections.primary().range().0;
let query = Self::occurrence_query(needle);
let Some(hit) = self.buffer.find_next(&query, from) else {
return Some(Vec::new());
};
if self.selections.iter().any(|s| s.range() == hit.range()) {
return Some(Vec::new());
}
self.selections.push(hit);
self.scroll_to_cursor();
Some(vec![PanelEvent::NeedsRedraw])
}
pub(crate) fn select_all_occurrences(&mut self) -> Option<Vec<PanelEvent>> {
self.select_word_under_caret();
let Some(needle) = self.occurrence_needle() else {
return Some(Vec::new());
};
let query = Self::occurrence_query(needle);
let hits = self.buffer.find_all(&query);
let Some((first, rest)) = hits.split_first() else {
return Some(Vec::new());
};
self.selections.set_single(*first);
for hit in rest {
self.selections.push(*hit);
}
self.scroll_to_cursor();
Some(vec![PanelEvent::NeedsRedraw])
}
}