ftml/render/text/
context.rs1use crate::data::PageInfo;
22use crate::non_empty_vec::NonEmptyVec;
23use crate::render::Handle;
24use crate::settings::WikitextSettings;
25use crate::tree::{Bibliography, BibliographyList, Element, VariableScopes};
26use std::fmt::{self, Write};
27use std::num::NonZeroUsize;
28
29#[derive(Debug)]
30pub struct TextContext<'i, 'h, 'e, 't>
31where
32 'e: 't,
33{
34 output: String,
35 info: &'i PageInfo<'i>,
36 handle: &'h Handle,
37 settings: &'e WikitextSettings,
38
39 variables: VariableScopes,
43
44 table_of_contents: &'e [Element<'t>],
48 footnotes: &'e [Vec<Element<'t>>],
49 bibliographies: &'e BibliographyList<'t>,
50
51 prefixes: Vec<&'static str>,
56
57 list_depths: NonEmptyVec<usize>,
59
60 invisible: usize,
64
65 equation_index: NonZeroUsize,
67
68 footnote_index: NonZeroUsize,
70}
71
72impl<'i, 'h, 'e, 't> TextContext<'i, 'h, 'e, 't>
73where
74 'e: 't,
75{
76 #[inline]
77 pub fn new(
78 info: &'i PageInfo<'i>,
79 handle: &'h Handle,
80 settings: &'e WikitextSettings,
81 table_of_contents: &'e [Element<'t>],
82 footnotes: &'e [Vec<Element<'t>>],
83 bibliographies: &'e BibliographyList<'t>,
84 wikitext_len: usize,
85 ) -> Self {
86 TextContext {
87 output: String::with_capacity(wikitext_len),
88 info,
89 handle,
90 settings,
91 variables: VariableScopes::new(),
92 table_of_contents,
93 footnotes,
94 bibliographies,
95 prefixes: Vec::new(),
96 list_depths: NonEmptyVec::new(1),
97 invisible: 0,
98 equation_index: NonZeroUsize::new(1).unwrap(),
99 footnote_index: NonZeroUsize::new(1).unwrap(),
100 }
101 }
102
103 #[inline]
105 pub fn buffer(&mut self) -> &mut String {
106 &mut self.output
107 }
108
109 #[inline]
110 pub fn info(&self) -> &'i PageInfo<'i> {
111 self.info
112 }
113
114 #[inline]
115 pub fn settings(&self) -> &WikitextSettings {
116 self.settings
117 }
118
119 #[inline]
120 pub fn language(&self) -> &str {
121 &self.info.language
122 }
123
124 #[inline]
125 pub fn handle(&self) -> &'h Handle {
126 self.handle
127 }
128
129 #[inline]
130 pub fn variables(&self) -> &VariableScopes {
131 &self.variables
132 }
133
134 #[inline]
135 pub fn variables_mut(&mut self) -> &mut VariableScopes {
136 &mut self.variables
137 }
138
139 #[inline]
140 pub fn table_of_contents(&self) -> &'e [Element<'t>] {
141 self.table_of_contents
142 }
143
144 #[inline]
145 pub fn footnotes(&self) -> &'e [Vec<Element<'t>>] {
146 self.footnotes
147 }
148
149 #[inline]
150 pub fn get_bibliography(&self, index: usize) -> &'e Bibliography<'t> {
151 self.bibliographies.get_bibliography(index)
152 }
153
154 pub fn get_bibliography_ref(
155 &self,
156 label: &str,
157 ) -> Option<(usize, &'e [Element<'t>])> {
158 self.bibliographies.get_reference(label)
159 }
160
161 pub fn next_equation_index(&mut self) -> NonZeroUsize {
162 let index = self.equation_index;
163 self.equation_index = NonZeroUsize::new(index.get() + 1).unwrap();
164 index
165 }
166
167 pub fn next_footnote_index(&mut self) -> NonZeroUsize {
168 let index = self.footnote_index;
169 self.footnote_index = NonZeroUsize::new(index.get() + 1).unwrap();
170 index
171 }
172
173 #[inline]
175 pub fn push_prefix(&mut self, prefix: &'static str) {
176 self.prefixes.push(prefix);
177 }
178
179 #[inline]
180 pub fn pop_prefix(&mut self) {
181 self.prefixes.pop();
182 }
183
184 #[inline]
186 pub fn list_depth(&self) -> usize {
187 self.list_depths.len()
188 }
189
190 #[inline]
191 pub fn incr_list_depth(&mut self) {
192 self.list_depths.push(1);
193 }
194
195 #[inline]
196 pub fn decr_list_depth(&mut self) {
197 self.list_depths.pop();
198 }
199
200 pub fn next_list_index(&mut self) -> usize {
201 let index = *self.list_depths.last();
202 *self.list_depths.last_mut() += 1;
203 index
204 }
205
206 #[inline]
208 fn invisible(&self) -> bool {
209 self.invisible > 0
210 }
211
212 #[inline]
213 pub fn enable_invisible(&mut self) {
214 self.invisible += 1;
215 }
216
217 #[inline]
218 pub fn disable_invisible(&mut self) {
219 self.invisible -= 1;
220 }
221
222 pub fn push(&mut self, ch: char) {
224 if self.invisible() {
225 self.output.push(' ');
226 } else {
227 self.output.push(ch);
228 }
229 }
230
231 pub fn push_str(&mut self, s: &str) {
232 if self.invisible() {
233 let chars = s.chars().count();
234 for _ in 0..chars {
235 self.output.push(' ');
236 }
237 } else {
238 self.output.push_str(s);
239 }
240 }
241
242 pub fn add_newline(&mut self) {
243 self.output.push('\n');
244
245 for prefix in &self.prefixes {
246 self.output.push_str(prefix);
247 }
248 }
249
250 #[inline]
251 pub fn ends_with_newline(&self) -> bool {
252 self.output.ends_with('\n')
253 }
254}
255
256impl<'i, 'h, 'e, 't> From<TextContext<'i, 'h, 'e, 't>> for String {
257 #[inline]
258 fn from(ctx: TextContext<'i, 'h, 'e, 't>) -> String {
259 ctx.output
260 }
261}
262
263impl<'e, 't> Write for TextContext<'_, '_, 'e, 't>
264where
265 'e: 't,
266{
267 #[inline]
268 fn write_str(&mut self, s: &str) -> fmt::Result {
269 self.buffer().write_str(s)
270 }
271}