1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*!
Attribute runs of a message body's `NSAttributedString`.
*/
use crate::;
/// One attribute run of a message's [`NSAttributedString`](crate::util::typedstream)
/// body: a byte range into the [`Message`](crate::tables::messages::Message)'s [`text`](crate::tables::messages::Message::text)
/// plus every attribute applied to it.
///
/// A range is a *text* range when [`attachment`](Self::attachment) is `None` and
/// an *attachment* range (a `\u{FFFC}` placeholder for an inline attachment)
/// when it is `Some`. Effects, styles, and the inline-emoji hint apply to either
/// kind. The [`typedstream`](crate::util::typedstream) attribute dictionary is a flat bag, so an attachment
/// range can also carry, say, an [`Animated`](TextEffect::Animated) effect.
///
/// Ranges that share a `__kIMMessagePartAttributeName` index are grouped into one
/// [`BubbleComponent::Run`](crate::tables::messages::models::BubbleComponent::Run). For example, message text with a
/// [`Mention`](TextEffect::Mention) like:
///
/// ```
/// let message_text = "What's up, Christopher?";
/// ```
///
/// parses into a single run of 3 ranges:
///
/// ```
/// use imessage_database::message_types::text_effects::text_effect::TextEffect;
/// use imessage_database::tables::messages::models::{AttributedRange, BubbleComponent};
///
/// let result = vec![BubbleComponent::Run(vec![
/// AttributedRange::text(0, 11, vec![TextEffect::Default]), // `What's up, `
/// AttributedRange::text(11, 22, vec![TextEffect::Mention("+5558675309".to_string())]), // `Christopher`
/// AttributedRange::text(22, 23, vec![TextEffect::Default]) // `?`
/// ])];
/// ```