1use crate::{components::omdoc::OMDocT, FTMLString, FTMLStringMath};
2use flams_ontology::{
3 content::{declarations::symbols::ArgSpec, terms::Term},
4 narration::{
5 paragraphs::{ParagraphFormatting, ParagraphKind},
6 problems::CognitiveDimension,
7 },
8 uris::{DocumentElementURI, DocumentURI, ModuleURI, NarrativeURI, SymbolURI, URI},
9};
10use flams_utils::vecmap::{VecMap, VecSet};
11
12use super::{
13 content::{OMDocExtension, OMDocModule, OMDocMorphism, OMDocStructure, OMDocSymbol},
14 OMDoc,
15};
16use flams_web_utils::components::{Block, Header, HeaderLeft, HeaderRight, LazyCollapsible};
17use leptos::{either::Either, prelude::*};
18use thaw::{Text, TextTag};
19
20#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
21#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
22#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
23pub struct OMDocDocument {
24 pub uri: DocumentURI,
25 pub title: Option<String>,
26 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
27 pub uses: VecSet<ModuleURI>,
28 pub children: Vec<OMDocDocumentElement>,
29}
30impl super::OMDocT for OMDocDocument {
31 fn into_view(self) -> impl IntoView {
32 view! {<Block show_separator=false>
33 <HeaderLeft slot>{super::uses("Uses",self.uses.0)}</HeaderLeft>
34 {self.children.into_iter().map(super::OMDocT::into_view).collect_view()}
35 </Block>}
36 }
37}
38impl From<OMDocDocument> for OMDoc {
39 #[inline]
40 fn from(value: OMDocDocument) -> Self {
41 Self::Document(value)
42 }
43}
44
45#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
46#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
47#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
48pub struct OMDocSection {
49 pub title: Option<String>,
50 pub uri: DocumentElementURI,
51 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
52 pub uses: VecSet<ModuleURI>,
53 pub children: Vec<OMDocDocumentElement>,
54}
55impl super::OMDocT for OMDocSection {
56 fn into_view(self) -> impl IntoView {
57 if let Some(title) = self.title {
58 Either::Left(view! {
59 <Block>
60 <Header slot><b style="font-size:larger"><FTMLString html=title/></b></Header>
61 <HeaderLeft slot>{super::uses("Uses",self.uses.0)}</HeaderLeft>
62 {self.children.into_iter().map(super::OMDocT::into_view).collect_view()}
63 </Block>
64 })
65 } else {
66 Either::Right(
67 self.children
68 .into_iter()
69 .map(super::OMDocT::into_view)
70 .collect_view(),
71 )
72 }
73 }
74}
75impl From<OMDocSection> for OMDoc {
76 #[inline]
77 fn from(value: OMDocSection) -> Self {
78 Self::Section(value)
79 }
80}
81impl From<OMDocSection> for OMDocDocumentElement {
82 #[inline]
83 fn from(value: OMDocSection) -> Self {
84 Self::Section(value)
85 }
86}
87
88#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
89#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
90#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
91pub struct OMDocSlide {
92 pub uri: DocumentElementURI,
93 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
94 pub uses: VecSet<ModuleURI>,
95 pub children: Vec<OMDocDocumentElement>,
96}
97impl super::OMDocT for OMDocSlide {
98 fn into_view(self) -> impl IntoView {
99 view! {
100 <Block>
101 <Header slot><b style="font-size:larger">"Slide"</b></Header>
102 <HeaderLeft slot>{super::uses("Uses",self.uses.0)}</HeaderLeft>
103 {self.children.into_iter().map(super::OMDocT::into_view).collect_view()}
104 </Block>
105 }
106 }
107}
108
109impl From<OMDocSlide> for OMDoc {
110 #[inline]
111 fn from(value: OMDocSlide) -> Self {
112 Self::Slide(value)
113 }
114}
115impl From<OMDocSlide> for OMDocDocumentElement {
116 #[inline]
117 fn from(value: OMDocSlide) -> Self {
118 Self::Slide(value)
119 }
120}
121
122#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
123#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
124#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
125pub struct OMDocVariable {
126 pub uri: DocumentElementURI,
127 pub arity: ArgSpec,
128 pub macro_name: Option<String>,
129 pub tp: Option<Term>, pub df: Option<Term>, pub is_seq: bool,
132}
133impl super::OMDocT for OMDocVariable {
134 fn into_view(self) -> impl IntoView {
135 let OMDocVariable {
136 uri,
137 df,
138 tp,
139 arity,
140 is_seq,
141 macro_name,
142 } = self;
143 let varstr = if is_seq {
145 "Sequence Variable "
146 } else {
147 "Variable "
148 };
149 let name = uri.name().last_name().to_string();
150 view! {
151 <Block show_separator=false>
152 <Header slot><span>
153 <b>{varstr}<span class="ftml-var-comp">{name}</span></b>
154 {macro_name.map(|name| view!(<span>" ("<Text tag=TextTag::Code>"\\"{name}</Text>")"</span>))}
155 {tp.map(|t| view! {
156 " of type "{
157 crate::remote::get!(present(t.clone()) = html => {
158 view!(<FTMLStringMath html/>)
159 })
160 }
161 })}
162 </span></Header>
163 <HeaderLeft slot>
164 {super::content::do_notations(URI::Narrative(uri.into()),arity)}
165 </HeaderLeft>
166 <HeaderRight slot><span style="white-space:nowrap;">{df.map(|t| view! {
167 "Definiens: "{
168 crate::remote::get!(present(t.clone()) = html => {
169 view!(<FTMLStringMath html/>)
170 })
171 }
172 })}</span></HeaderRight>
173 <span/>
174 </Block>
175 }
176 }
177}
178impl From<OMDocVariable> for OMDoc {
179 #[inline]
180 fn from(value: OMDocVariable) -> Self {
181 Self::Variable(value)
182 }
183}
184impl From<OMDocVariable> for OMDocDocumentElement {
185 #[inline]
186 fn from(value: OMDocVariable) -> Self {
187 Self::Variable(value)
188 }
189}
190
191#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
192#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
193#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
194pub struct OMDocParagraph {
195 pub uri: DocumentElementURI,
196 pub kind: ParagraphKind,
197 pub formatting: ParagraphFormatting,
198 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
199 pub uses: VecSet<ModuleURI>,
200 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
201 pub fors: VecMap<SymbolURI, Option<Term>>, pub title: Option<String>,
203 pub children: Vec<OMDocDocumentElement>,
204 pub definition_like: bool,
205}
206impl super::OMDocT for OMDocParagraph {
207 fn into_view(self) -> impl IntoView {
208 let Self {
209 uri,
210 kind,
211 uses,
212 fors,
213 title,
214 children,
215 definition_like,
216 ..
217 } = self;
218 let title = title.unwrap_or_else(|| uri.name().last_name().to_string());
219 view! {
220 <Block>
221 <Header slot><b>
222 {super::doc_elem_name(uri,Some(kind.as_display_str()),title)}
223 </b></Header>
224 <HeaderLeft slot>{super::uses("Uses",uses.0)}</HeaderLeft>
225 <HeaderRight slot>{super::comma_sep(
226 if definition_like {"Defines"} else {"Concerns"},
227 fors.into_iter().map(|(k,t)| view!{
228 {super::symbol_name(&k,k.name().last_name().as_ref())}
229 {t.map(|t| view!{" as "{
230 crate::remote::get!(present(t.clone()) = html => {
231 view!(<FTMLStringMath html/>)
232 })
233 }})}
234 })
235 )}</HeaderRight>
236 {children.into_iter().map(super::OMDocT::into_view).collect_view()}
237 </Block>
238 }
239 }
240}
241impl From<OMDocParagraph> for OMDoc {
242 #[inline]
243 fn from(value: OMDocParagraph) -> Self {
244 Self::Paragraph(value)
245 }
246}
247impl From<OMDocParagraph> for OMDocDocumentElement {
248 #[inline]
249 fn from(value: OMDocParagraph) -> Self {
250 Self::Paragraph(value)
251 }
252}
253
254#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
255#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
256#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
257pub struct OMDocProblem {
258 pub uri: DocumentElementURI,
259 pub sub_problem: bool,
260 pub autogradable: bool,
261 pub points: Option<f32>,
262 pub title: Option<String>,
263 pub preconditions: Vec<(CognitiveDimension, SymbolURI)>,
264 pub objectives: Vec<(CognitiveDimension, SymbolURI)>,
265 #[cfg_attr(feature = "ts", tsify(type = "ModuleURI[]"))]
266 pub uses: VecSet<ModuleURI>,
267 pub children: Vec<OMDocDocumentElement>,
268}
269impl super::OMDocT for OMDocProblem {
270 fn into_view(self) -> impl IntoView {
271 let Self {
272 uri,
273 title,
274 uses,
275 objectives,
276 children,
277 ..
278 } = self;
279 let title = title.unwrap_or_else(|| uri.name().last_name().to_string());
280 view! {
281 <Block>
282 <Header slot><b>
283 {super::doc_elem_name(uri,Some("Problem"),title)}
284 </b></Header>
285 <HeaderLeft slot>{super::uses("Uses",uses.0)}</HeaderLeft>
286 <HeaderRight slot>{super::comma_sep(
287 "Objectives",
288 objectives.into_iter().map(|(dim,sym)| view!{
289 {super::symbol_name(&sym,sym.name().last_name().as_ref())}
290 " ("{dim.to_string()}")"
291 })
292 )}</HeaderRight>
293 {children.into_iter().map(super::OMDocT::into_view).collect_view()}
294 </Block>
295 }
296 }
297}
298impl From<OMDocProblem> for OMDoc {
299 #[inline]
300 fn from(value: OMDocProblem) -> Self {
301 Self::Problem(value)
302 }
303}
304impl From<OMDocProblem> for OMDocDocumentElement {
305 #[inline]
306 fn from(value: OMDocProblem) -> Self {
307 Self::Problem(value)
308 }
309}
310
311#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
312#[serde(tag = "type")]
313#[cfg_attr(feature = "ts", derive(tsify_next::Tsify))]
314#[cfg_attr(feature = "ts", tsify(into_wasm_abi, from_wasm_abi))]
315pub enum OMDocDocumentElement {
316 Slide(OMDocSlide),
317 Section(OMDocSection),
318 Module(OMDocModule<OMDocDocumentElement>),
319 Morphism(OMDocMorphism<OMDocDocumentElement>),
320 Structure(OMDocStructure<OMDocDocumentElement>),
321 Extension(OMDocExtension<OMDocDocumentElement>),
322 DocumentReference {
323 uri: DocumentURI,
324 title: Option<String>,
325 },
326 Variable(OMDocVariable),
327 Paragraph(OMDocParagraph),
328 Problem(OMDocProblem),
329 TopTerm {
330 uri: DocumentElementURI,
331 term: Term,
332 },
333 SymbolDeclaration(
334 #[cfg_attr(feature = "ts", tsify(type = "SymbolURI|OMDocSymbol"))]
335 either::Either<SymbolURI, OMDocSymbol>,
336 ),
337}
338impl super::sealed::Sealed for OMDocDocumentElement {}
339impl super::OMDocDecl for OMDocDocumentElement {}
340impl super::OMDocT for OMDocDocumentElement {
341 fn into_view(self) -> impl IntoView {
342 match self {
343 Self::Slide(s) => s.into_view().into_any(),
344 Self::Section(s) => s.into_view().into_any(),
345 Self::Module(m) => m.into_view().into_any(),
346 Self::Morphism(m) => m.into_view().into_any(),
347 Self::Structure(s) => s.into_view().into_any(),
348 Self::Extension(e) => e.into_view().into_any(),
349 Self::DocumentReference { uri, title } => doc_ref(uri, title).into_any(),
350 Self::Variable(v) => v.into_view().into_any(),
351 Self::Paragraph(p) => p.into_view().into_any(),
352 Self::Problem(e) => e.into_view().into_any(),
353 Self::TopTerm { term, .. } => view! {
354 <Block show_separator=false>
355 <Header slot><span><b>"Term "</b>{
356 crate::remote::get!(present(term.clone()) = html => {
357 view!(<FTMLStringMath html/>)
358 })
359 }</span></Header>
360 ""
361 </Block>
362 }
363 .into_any(),
364 Self::SymbolDeclaration(either::Right(s)) => s.into_view().into_any(),
365 Self::SymbolDeclaration(either::Left(u)) => {
366 view! {<div style="color:red;">"Symbol "{u.to_string()}" not found"</div>}
367 .into_any()
368 }
369 }
370 }
371}
372
373pub(crate) fn doc_ref(uri: DocumentURI, title: Option<String>) -> impl IntoView {
374 let name = title.unwrap_or_else(|| uri.name().last_name().to_string());
375 let uricl = uri.clone();
376 view! {<LazyCollapsible>
378 <Header slot><b>"Document "{super::doc_name(&uri, name)}</b></Header>
379 <div style="padding-left:15px;">{
380 let uri = uricl.clone();
381 let r = Resource::new(|| (),move |()| crate::remote::server_config.omdoc(NarrativeURI::Document(uri.clone()).into()));
382 view!{
383 <Suspense fallback=|| view!(<flams_web_utils::components::Spinner/>)>{move || {
384 if let Some(Ok((_,omdoc))) = r.get() {
385 let OMDoc::Document(omdoc) = omdoc else {unreachable!()};
386 Some(omdoc.into_view())
387 } else {None}
388 }}</Suspense>
389 }
390 }</div>
391 </LazyCollapsible>
392 } }
394
395impl From<OMDocDocumentElement> for OMDoc {
396 fn from(value: OMDocDocumentElement) -> Self {
397 match value {
398 OMDocDocumentElement::Slide(s) => Self::Slide(s),
399 OMDocDocumentElement::Section(s) => Self::Section(s),
400 OMDocDocumentElement::Module(m) => Self::DocModule(m),
401 OMDocDocumentElement::Morphism(m) => Self::DocMorphism(m),
402 OMDocDocumentElement::Structure(s) => Self::DocStructure(s),
403 OMDocDocumentElement::Extension(e) => Self::DocExtension(e),
404 OMDocDocumentElement::DocumentReference { uri, title } => {
405 Self::DocReference { uri, title }
406 }
407 OMDocDocumentElement::SymbolDeclaration(either::Right(s)) => Self::SymbolDeclaration(s),
408 OMDocDocumentElement::Variable(v) => Self::Variable(v),
409 OMDocDocumentElement::Paragraph(p) => Self::Paragraph(p),
410 OMDocDocumentElement::Problem(e) => Self::Problem(e),
411 OMDocDocumentElement::TopTerm { uri, term } => Self::Term { uri, term },
412 OMDocDocumentElement::SymbolDeclaration(either::Left(u)) => Self::Other(u.to_string()),
413 }
414 }
415}
416
417#[cfg(feature = "ssr")]
418mod froms {
419 use super::{
420 OMDocDocument, OMDocDocumentElement, OMDocParagraph, OMDocProblem, OMDocSection,
421 OMDocSlide, OMDocVariable,
422 };
423 use crate::components::omdoc::content::{
424 OMDocExtension, OMDocModule, OMDocMorphism, OMDocStructure, OMDocSymbol,
425 };
426 use flams_ontology::{
427 content::{declarations::OpenDeclaration, ModuleLike},
428 narration::{
429 documents::Document, paragraphs::LogicalParagraph, problems::Problem,
430 sections::Section, variables::Variable, DocumentElement, NarrationTrait,
431 },
432 uris::{DocumentElementURI, ModuleURI},
433 Checked,
434 };
435 use flams_system::backend::Backend;
436 use flams_utils::{vecmap::VecSet, CSS};
437
438 impl OMDocSection {
439 pub fn from_section<B: Backend>(
440 Section {
441 title,
442 children,
443 uri,
444 ..
445 }: &Section<Checked>,
446 backend: &B, css: &mut VecSet<CSS>,
448 ) -> Self {
449 let mut uses = VecSet::new();
450 let mut imports = VecSet::new();
451 let title = title.and_then(|r| {
452 if let Some((c, s)) = backend.get_html_fragment(uri.document(), r) {
453 if s.trim().is_empty() {
454 None
455 } else {
456 for c in c {
457 css.insert(c)
458 }
459 Some(s)
460 }
461 } else {
462 None
463 }
464 });
465 let children =
466 OMDocDocumentElement::do_children(backend, children, &mut uses, &mut imports, css);
467 Self {
468 title,
469 uri: uri.clone(),
470 uses,
471 children,
472 }
473 }
474 }
475
476 impl OMDocSlide {
477 pub fn from_slide<B: Backend>(
478 children: &[DocumentElement<Checked>],
479 uri: &DocumentElementURI,
480 backend: &B, css: &mut VecSet<CSS>,
482 ) -> Self {
483 let mut uses = VecSet::new();
484 let mut imports = VecSet::new();
485 let children =
486 OMDocDocumentElement::do_children(backend, children, &mut uses, &mut imports, css);
487 Self {
488 uri: uri.clone(),
489 uses,
490 children,
491 }
492 }
493 }
494
495 impl OMDocParagraph {
496 pub fn from_paragraph<B: Backend>(
497 LogicalParagraph {
498 uri,
499 kind,
500 formatting,
501 fors,
502 title,
503 children,
504 styles,
505 ..
506 }: &LogicalParagraph<Checked>,
507 backend: &B, css: &mut VecSet<CSS>,
509 ) -> Self {
510 let definition_like = kind.is_definition_like(styles);
511 let mut uses = VecSet::new();
512 let mut imports = VecSet::new();
513 let title = title.and_then(|r| {
514 if let Some((c, s)) = backend.get_html_fragment(uri.document(), r) {
515 if s.trim().is_empty() {
516 None
517 } else {
518 for c in c {
519 css.insert(c)
520 }
521 Some(s)
522 }
523 } else {
524 None
525 }
526 });
527 let children =
528 OMDocDocumentElement::do_children(backend, children, &mut uses, &mut imports, css);
529 Self {
530 kind: *kind,
531 formatting: *formatting,
532 fors: fors.clone(), title,
534 uri: uri.clone(),
535 uses,
536 children,
537 definition_like,
538 }
539 }
540 }
541
542 impl OMDocProblem {
543 #[allow(clippy::cast_possible_truncation)]
544 pub fn from_problem<B: Backend>(
545 Problem {
546 uri,
547 sub_problem,
548 autogradable,
549 points,
550 title,
551 preconditions,
552 objectives,
553 children,
554 ..
555 }: &Problem<Checked>,
556 backend: &B, css: &mut VecSet<CSS>,
558 ) -> Self {
559 let mut uses = VecSet::new();
560 let mut imports = VecSet::new();
561 let title = title.and_then(|r| {
562 if let Some((c, s)) = backend.get_html_fragment(uri.document(), r) {
563 if s.trim().is_empty() {
564 None
565 } else {
566 for c in c {
567 css.insert(c)
568 }
569 Some(s)
570 }
571 } else {
572 None
573 }
574 });
575 let children =
576 OMDocDocumentElement::do_children(backend, children, &mut uses, &mut imports, css);
577 Self {
578 sub_problem: *sub_problem,
579 autogradable: *autogradable,
580 points: *points,
581 preconditions: preconditions.to_vec(),
582 objectives: objectives.to_vec(),
583 title,
584 uri: uri.clone(),
585 uses,
586 children,
587 }
588 }
589 }
590
591 impl OMDocVariable {
592 pub fn from_variable<B: Backend>(
593 Variable {
594 uri,
595 arity,
596 macroname,
597 tp,
598 df,
599 is_seq,
600 ..
601 }: &Variable,
602 _backend: &B, ) -> Self {
604 Self {
605 uri: uri.clone(),
606 arity: arity.clone(),
607 macro_name: macroname.as_ref().map(ToString::to_string),
608 tp: tp.clone(), df: df.clone(), is_seq: *is_seq,
611 }
612 }
613 }
614
615 impl OMDocDocumentElement {
616 pub fn from_element<B: Backend>(
617 e: &DocumentElement<Checked>,
618 backend: &B, css: &mut VecSet<CSS>,
620 ) -> Option<Self> {
621 match e {
622 DocumentElement::Section(s) => {
623 Some(OMDocSection::from_section(s, backend, css).into())
624 }
625 DocumentElement::Paragraph(p) => {
626 Some(OMDocParagraph::from_paragraph(p, backend, css).into())
627 }
628 DocumentElement::Problem(p) => {
629 Some(OMDocProblem::from_problem(p, backend, css).into())
630 }
631 _ => None,
632 }
633 }
634
635 fn do_children<B: Backend>(
636 backend: &B, children: &[DocumentElement<Checked>],
638 uses: &mut VecSet<ModuleURI>,
639 imports: &mut VecSet<ModuleURI>,
640 css: &mut VecSet<CSS>,
641 ) -> Vec<Self> {
642 let mut ret = Vec::new();
643 for c in children {
644 match c {
645 DocumentElement::SkipSection(s) => {
646 ret.extend(Self::do_children(backend, s, uses, imports, css).into_iter())
647 }
648 DocumentElement::Section(s) => {
649 ret.push(OMDocSection::from_section(s, backend, css).into());
650 }
651 DocumentElement::Slide { children, uri, .. } => {
652 ret.push(OMDocSlide::from_slide(children, uri, backend, css).into())
653 }
654 DocumentElement::Paragraph(p) => {
655 ret.push(OMDocParagraph::from_paragraph(p, backend, css).into());
656 }
657 DocumentElement::Problem(p) => {
658 ret.push(OMDocProblem::from_problem(p, backend, css).into());
659 }
660 DocumentElement::Module {
661 module, children, ..
662 } => {
663 let uri = module.id().into_owned();
664 let (metatheory, signature) =
665 if let Some(ModuleLike::Module(m)) = module.get() {
666 (
667 m.meta().map(|c| c.id().into_owned()),
668 m.signature().map(|c| c.id().into_owned()),
669 )
670 } else {
671 (None, None)
672 };
673 let mut uses = VecSet::new();
674 let mut imports = VecSet::new();
675 let children =
676 Self::do_children(backend, children, &mut uses, &mut imports, css);
677 ret.push(Self::Module(OMDocModule {
678 uri,
679 imports,
680 uses,
681 metatheory,
682 signature,
683 children,
684 }));
685 }
686 DocumentElement::Morphism {
687 morphism, children, ..
688 } => {
689 let uri = morphism.id().into_owned();
690 let (total, target) = morphism.get().map_or((false, None), |m| {
691 (m.as_ref().total, Some(m.as_ref().domain.id().into_owned()))
692 });
693 let mut uses = VecSet::new();
694 let mut imports = VecSet::new();
695 let children =
696 Self::do_children(backend, children, &mut uses, &mut imports, css);
697 ret.push(Self::Morphism(OMDocMorphism {
698 uri,
699 total,
700 target,
701 uses,
702 children,
703 }));
704 }
705 DocumentElement::MathStructure {
706 structure,
707 children,
708 ..
709 } => {
710 let uri = structure.id().into_owned();
711 let macroname = structure
712 .get()
713 .and_then(|s| s.as_ref().macroname.as_ref().map(ToString::to_string));
714 let extensions = super::super::froms::get_extensions(backend, &uri)
715 .map(|e| {
716 (
717 e.as_ref().uri.clone(),
718 e.as_ref()
719 .elements
720 .iter()
721 .filter_map(|e| {
722 if let OpenDeclaration::Symbol(s) = e {
723 Some(OMDocSymbol::from_symbol(s, backend))
724 } else {
725 None
726 }
727 })
728 .collect(),
729 )
730 })
731 .collect();
732 let mut uses = VecSet::new();
733 let mut imports = VecSet::new();
734 let children =
735 Self::do_children(backend, children, &mut uses, &mut imports, css);
736 ret.push(Self::Structure(OMDocStructure {
737 uri,
738 macro_name: macroname,
739 uses,
740 extends: imports,
741 children,
742 extensions,
743 }));
744 }
745 DocumentElement::Extension {
746 extension,
747 target,
748 children,
749 ..
750 } => {
751 let target = target.id().into_owned();
752 let uri = extension.id().into_owned();
753 let mut uses = VecSet::new();
754 let mut imports = VecSet::new();
755 let children =
756 Self::do_children(backend, children, &mut uses, &mut imports, css);
757 ret.push(Self::Extension(OMDocExtension {
758 uri,
759 target,
760 uses,
761 children,
762 }));
763 }
764 DocumentElement::DocumentReference { target, .. } => {
765 let title = target
766 .get()
767 .and_then(|d| d.title().map(ToString::to_string));
768 let uri = target.id().into_owned();
769 ret.push(Self::DocumentReference { uri, title });
770 }
771 DocumentElement::SymbolDeclaration(s) => {
772 ret.push(Self::SymbolDeclaration(s.get().map_or_else(
773 || either::Left(s.id().into_owned()),
774 |s| either::Right(OMDocSymbol::from_symbol(s.as_ref(), backend)),
775 )));
776 }
777 DocumentElement::Variable(v) => {
778 ret.push(OMDocVariable::from_variable(v, backend).into());
779 }
780 DocumentElement::UseModule(m) => {
781 uses.insert(m.id().into_owned());
782 }
783 DocumentElement::ImportModule(m) => {
784 imports.insert(m.id().into_owned());
785 }
786 DocumentElement::TopTerm { term, uri, .. } => {
787 ret.push(Self::TopTerm {
788 term: term.clone(),
789 uri: uri.clone(),
790 }); }
792 DocumentElement::Definiendum { .. }
793 | DocumentElement::SymbolReference { .. }
794 | DocumentElement::VariableReference { .. }
795 | DocumentElement::Notation { .. }
796 | DocumentElement::VariableNotation { .. }
797 | DocumentElement::SetSectionLevel(_) => (),
798 }
799 }
800 ret
801 }
802 }
803
804 impl OMDocDocument {
805 pub fn from_document<B: Backend>(
806 d: &Document,
807 backend: &B, css: &mut VecSet<CSS>,
809 ) -> Self {
810 let uri = d.uri().clone();
811 let title = d.title().map(ToString::to_string);
812 let mut uses = VecSet::new();
813 let mut imports = VecSet::new();
814 let children = OMDocDocumentElement::do_children(
815 backend,
816 d.children(),
817 &mut uses,
818 &mut imports,
819 css,
820 );
821 Self {
822 uri,
823 title,
824 uses,
825 children,
826 }
827 }
828 }
829}