use super::models::*;
pub fn search_document(document: &Document, query: &str) -> Vec<SearchResult> {
let mut results = Vec::new();
if query.is_empty() {
return results;
}
let query_lower = query.to_lowercase();
for (element_index, element) in document.elements.iter().enumerate() {
let text = match element {
DocumentElement::Heading { text, .. } => text,
DocumentElement::Paragraph { runs } => {
&runs.iter().map(|run| run.text.as_str()).collect::<String>()
}
DocumentElement::List { items, .. } => {
for item in items {
let item_text: String = item.runs.iter().map(|run| run.text.as_str()).collect();
let text_lower = item_text.to_lowercase();
if let Some(start_pos) = text_lower.find(&query_lower) {
results.push(SearchResult {
element_index,
text: item_text,
start_pos,
end_pos: start_pos + query.len(),
});
}
}
continue;
}
DocumentElement::Table { table } => {
for header in &table.headers {
let text_lower = header.content.to_lowercase();
if let Some(start_pos) = text_lower.find(&query_lower) {
results.push(SearchResult {
element_index,
text: header.content.clone(),
start_pos,
end_pos: start_pos + query.len(),
});
}
}
for row in &table.rows {
for cell in row {
let text_lower = cell.content.to_lowercase();
if let Some(start_pos) = text_lower.find(&query_lower) {
results.push(SearchResult {
element_index,
text: cell.content.clone(),
start_pos,
end_pos: start_pos + query.len(),
});
}
}
}
continue;
}
DocumentElement::Image { description, .. } => description,
DocumentElement::Equation { latex, .. } => latex,
DocumentElement::CodeBlock { text } => text,
DocumentElement::TextBox { lines } => {
let combined = lines.join(" ");
let text_lower = combined.to_lowercase();
if let Some(start_pos) = text_lower.find(&query_lower) {
results.push(SearchResult {
element_index,
text: combined,
start_pos,
end_pos: start_pos + query.len(),
});
}
continue;
}
DocumentElement::PageBreak => continue,
};
let text_lower = text.to_lowercase();
if let Some(start_pos) = text_lower.find(&query_lower) {
results.push(SearchResult {
element_index,
text: text.clone(),
start_pos,
end_pos: start_pos + query.len(),
});
}
}
results
}
pub fn generate_outline(document: &Document) -> Vec<OutlineItem> {
let mut outline = Vec::new();
for (index, element) in document.elements.iter().enumerate() {
if let DocumentElement::Heading {
level,
text,
number,
} = element
{
let title = if let Some(number) = number {
format!("{number} {text}")
} else {
text.clone()
};
outline.push(OutlineItem {
title,
level: *level,
element_index: index,
});
}
}
outline
}