uqa_analysis/highlight/
rich.rs1use super::{
10 render::{merge_spans, render, Span},
11 terms::Terms,
12 HighlightOptions,
13};
14use crate::{AnalysisError, AnalysisResult, CompiledAnalyzer};
15use uqa_core::memory::{Budgeted, BudgetedVec, MemoryBudget};
16
17pub fn highlight_compiled(
21 text: &str,
22 query_inputs: &[String],
23 analyzer: &CompiledAnalyzer,
24 opts: &HighlightOptions,
25) -> AnalysisResult<String> {
26 Ok(highlight_compiled_budgeted(
27 text,
28 query_inputs,
29 analyzer,
30 opts,
31 &MemoryBudget::new(usize::MAX),
32 || Ok(()),
33 )?
34 .into_parts()
35 .0)
36}
37
38pub fn highlight_compiled_budgeted(
42 text: &str,
43 query_inputs: &[String],
44 analyzer: &CompiledAnalyzer,
45 opts: &HighlightOptions,
46 budget: &MemoryBudget,
47 mut poll: impl FnMut() -> AnalysisResult<()>,
48) -> AnalysisResult<Budgeted<String>> {
49 poll()?;
50 if text.is_empty() || query_inputs.is_empty() {
51 return crate::allocation::copy_text(text, budget, &mut poll);
52 }
53 let mut terms = Terms::new(budget);
54 for query in query_inputs {
55 poll()?;
56 terms.append(
57 analyzer.analyze_tokens_budgeted(query, budget, &mut poll)?,
58 false,
59 &mut poll,
60 )?;
61 }
62 if terms.is_empty() {
63 return crate::allocation::copy_text(text, budget, &mut poll);
64 }
65 terms.sort_unique(&mut poll)?;
66 let source = analyzer.analyze_tokens_budgeted(text, budget, &mut poll)?;
67 let mut spans = BudgetedVec::new(budget);
68 for token in source.tokens() {
69 poll()?;
70 if !terms.contains(token.term(), &mut poll)? {
71 continue;
72 }
73 let range = &token
74 .offsets()
75 .ok_or(AnalysisError::MissingTokenOffsets)?
76 .utf8;
77 if range.start > range.end {
78 return Err(AnalysisError::InvalidTextSpan {
79 start: range.start,
80 end: range.end,
81 });
82 }
83 for offset in [range.start, range.end] {
84 if !text.is_char_boundary(offset) {
85 return Err(AnalysisError::InvalidTextOffset {
86 coordinate: "UTF-8",
87 offset,
88 length: text.len(),
89 });
90 }
91 }
92 if !range.is_empty() {
93 spans.push(Span::new(range.start, range.end))?;
94 }
95 }
96 drop(source);
97 drop(terms);
98 merge_spans(&mut spans, &mut poll)?;
99 render(text, spans, opts, budget, &mut poll)
100}