ass_core/analysis/events/text_analysis/analysis.rs
1//! `TextAnalysis` type definition and analysis entry points.
2//!
3//! Defines the [`TextAnalysis`] result structure plus the public `analyze`
4//! constructors. The bulk of the parsing logic lives in the `parser` submodule
5//! and the accessors plus Unicode helpers live in the `helpers` submodule.
6
7use crate::{
8 analysis::events::tags::{OverrideTag, TagDiagnostic},
9 Result,
10};
11
12#[cfg(feature = "plugins")]
13use crate::plugin::ExtensionRegistry;
14use alloc::{string::String, vec::Vec};
15
16/// Analysis results for dialogue text content
17///
18/// Contains extracted plain text, override tag information, and Unicode
19/// complexity indicators. Uses zero-copy references where possible.
20#[derive(Debug, Clone)]
21pub struct TextAnalysis<'a> {
22 /// Plain text with override tags removed
23 pub(super) plain_text: String,
24 /// Unicode character count
25 pub(super) char_count: usize,
26 /// Line count after processing linebreaks
27 pub(super) line_count: usize,
28 /// Contains bidirectional text (RTL scripts)
29 pub(super) has_bidi_text: bool,
30 /// Contains complex Unicode beyond basic Latin
31 pub(super) has_complex_unicode: bool,
32 /// Parsed override tags
33 pub(super) override_tags: Vec<OverrideTag<'a>>,
34 /// Parse diagnostics collected during analysis
35 pub(super) parse_diagnostics: Vec<TagDiagnostic<'a>>,
36}
37
38impl<'a> TextAnalysis<'a> {
39 /// Analyze dialogue text content comprehensively
40 ///
41 /// Extracts plain text, parses override tags, and analyzes Unicode
42 /// complexity. Uses zero-copy references for tag arguments.
43 ///
44 /// # Arguments
45 ///
46 /// * `text` - Original dialogue text with potential override tags
47 ///
48 /// # Returns
49 ///
50 /// Complete text analysis results or parsing error.
51 ///
52 /// # Example
53 ///
54 /// ```rust
55 /// # use ass_core::analysis::events::text_analysis::TextAnalysis;
56 /// let text = "Hello {\\b1}world{\\b0}!";
57 /// let analysis = TextAnalysis::analyze(text)?;
58 /// assert_eq!(analysis.plain_text(), "Hello world!");
59 /// assert_eq!(analysis.override_tags().len(), 2);
60 /// # Ok::<(), Box<dyn std::error::Error>>(())
61 /// ```
62 ///
63 /// # Errors
64 ///
65 /// Returns an error if text parsing fails or contains invalid override tags.
66 pub fn analyze(text: &'a str) -> Result<Self> {
67 #[cfg(feature = "plugins")]
68 return Self::analyze_with_registry(text, None);
69 #[cfg(not(feature = "plugins"))]
70 return Self::analyze_impl(text);
71 }
72
73 /// Analyze dialogue text content with extension registry support
74 ///
75 /// Same as [`analyze`](Self::analyze) but allows custom tag handlers via registry.
76 /// Unhandled tags fall back to standard processing.
77 ///
78 /// # Arguments
79 ///
80 /// * `text` - Original dialogue text with potential override tags
81 /// * `registry` - Optional registry for custom tag handlers
82 ///
83 /// # Returns
84 ///
85 /// Complete text analysis results or parsing error.
86 ///
87 /// # Errors
88 ///
89 /// Returns an error if text parsing fails or contains invalid override tags.
90 #[cfg(feature = "plugins")]
91 pub fn analyze_with_registry(
92 text: &'a str,
93 registry: Option<&ExtensionRegistry>,
94 ) -> Result<Self> {
95 Self::analyze_impl_with_registry(text, registry)
96 }
97
98 /// Internal implementation without plugins support
99 #[cfg(not(feature = "plugins"))]
100 fn analyze_impl(text: &'a str) -> Result<Self> {
101 Self::analyze_impl_with_registry(text)
102 }
103}