1use serde::{Deserialize, Serialize};
2
3use crate::entities::*;
4use crate::format_runs::{InlineContent, InlineSegment};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct FragmentData {
8 pub blocks: Vec<FragmentBlock>,
9 #[serde(default, skip_serializing_if = "Vec::is_empty")]
11 pub tables: Vec<FragmentTable>,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct FragmentTable {
17 pub rows: usize,
18 pub columns: usize,
19 pub cells: Vec<FragmentTableCell>,
20 #[serde(default)]
24 pub block_insert_index: usize,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
27 pub fmt_border: Option<i64>,
28 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub fmt_cell_spacing: Option<i64>,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub fmt_cell_padding: Option<i64>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub fmt_width: Option<i64>,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub fmt_alignment: Option<Alignment>,
36 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 pub column_widths: Vec<i64>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct FragmentTableCell {
43 pub row: usize,
44 pub column: usize,
45 pub row_span: usize,
46 pub column_span: usize,
47 pub blocks: Vec<FragmentBlock>,
48 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub fmt_padding: Option<i64>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub fmt_border: Option<i64>,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub fmt_vertical_alignment: Option<CellVerticalAlignment>,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub fmt_background_color: Option<String>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct FragmentBlock {
61 pub plain_text: String,
62 pub elements: Vec<FragmentElement>,
63 pub heading_level: Option<i64>,
64 pub list: Option<FragmentList>,
65 pub alignment: Option<Alignment>,
66 pub indent: Option<i64>,
67 pub text_indent: Option<i64>,
68 pub marker: Option<MarkerType>,
69 pub top_margin: Option<i64>,
70 pub bottom_margin: Option<i64>,
71 pub left_margin: Option<i64>,
72 pub right_margin: Option<i64>,
73 pub tab_positions: Vec<i64>,
74 pub line_height: Option<i64>,
75 pub non_breakable_lines: Option<bool>,
76 #[serde(default)]
79 pub page_break_before: Option<bool>,
80 pub direction: Option<TextDirection>,
81 pub background_color: Option<String>,
82 pub is_code_block: Option<bool>,
83 pub code_language: Option<String>,
84 #[serde(default)]
85 pub hyphenate: Option<bool>,
86 #[serde(default)]
87 pub language: Option<String>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct FragmentElement {
92 pub content: InlineContent,
93 pub fmt_font_family: Option<String>,
94 pub fmt_font_point_size: Option<i64>,
95 pub fmt_font_weight: Option<i64>,
96 pub fmt_font_bold: Option<bool>,
97 pub fmt_font_italic: Option<bool>,
98 pub fmt_font_underline: Option<bool>,
99 pub fmt_font_overline: Option<bool>,
100 pub fmt_font_strikeout: Option<bool>,
101 pub fmt_letter_spacing: Option<i64>,
102 pub fmt_word_spacing: Option<i64>,
103 pub fmt_anchor_href: Option<String>,
104 pub fmt_anchor_names: Vec<String>,
105 pub fmt_is_anchor: Option<bool>,
106 pub fmt_tooltip: Option<String>,
107 pub fmt_underline_style: Option<UnderlineStyle>,
108 pub fmt_vertical_alignment: Option<CharVerticalAlignment>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct FragmentList {
113 pub style: ListStyle,
114 pub indent: i64,
115 pub prefix: String,
116 pub suffix: String,
117}
118
119impl FragmentElement {
120 pub fn from_segment(seg: &InlineSegment) -> Self {
121 FragmentElement {
122 content: seg.content.clone(),
123 fmt_font_family: seg.fmt_font_family.clone(),
124 fmt_font_point_size: seg.fmt_font_point_size,
125 fmt_font_weight: seg.fmt_font_weight,
126 fmt_font_bold: seg.fmt_font_bold,
127 fmt_font_italic: seg.fmt_font_italic,
128 fmt_font_underline: seg.fmt_font_underline,
129 fmt_font_overline: seg.fmt_font_overline,
130 fmt_font_strikeout: seg.fmt_font_strikeout,
131 fmt_letter_spacing: seg.fmt_letter_spacing,
132 fmt_word_spacing: seg.fmt_word_spacing,
133 fmt_anchor_href: seg.fmt_anchor_href.clone(),
134 fmt_anchor_names: seg.fmt_anchor_names.clone(),
135 fmt_is_anchor: seg.fmt_is_anchor,
136 fmt_tooltip: seg.fmt_tooltip.clone(),
137 fmt_underline_style: seg.fmt_underline_style.clone(),
138 fmt_vertical_alignment: seg.fmt_vertical_alignment.clone(),
139 }
140 }
141}
142
143impl FragmentBlock {
144 pub fn is_inline_only(&self) -> bool {
147 self.heading_level.is_none()
148 && self.list.is_none()
149 && self.alignment.is_none()
150 && self.indent.unwrap_or(0) == 0
151 && self.text_indent.unwrap_or(0) == 0
152 && self.marker.is_none()
153 && self.top_margin.is_none()
154 && self.bottom_margin.is_none()
155 && self.left_margin.is_none()
156 && self.right_margin.is_none()
157 && self.line_height.is_none()
158 && self.non_breakable_lines.is_none()
159 && self.direction.is_none()
160 && self.background_color.is_none()
161 && self.is_code_block.is_none()
162 && self.code_language.is_none()
163 && self.hyphenate.is_none()
164 && self.language.is_none()
165 }
166}
167
168impl FragmentList {
169 pub fn from_entity(list: &List) -> Self {
170 FragmentList {
171 style: list.style.clone(),
172 indent: list.indent,
173 prefix: list.prefix.clone(),
174 suffix: list.suffix.clone(),
175 }
176 }
177
178 pub fn to_entity(&self) -> List {
179 List {
180 id: 0,
181 created_at: chrono::Utc::now(),
182 updated_at: chrono::Utc::now(),
183 style: self.style.clone(),
184 indent: self.indent,
185 prefix: self.prefix.clone(),
186 suffix: self.suffix.clone(),
187 }
188 }
189}