flams_ontology/narration/
paragraphs.rs

1use std::{fmt::Display, str::FromStr};
2
3use flams_utils::vecmap::VecMap;
4
5use crate::{
6    content::terms::Term,
7    ftml::FTMLKey,
8    uris::{DocumentElementURI, Name, SymbolURI},
9    Checked, CheckingState, DocumentRange,
10};
11
12use super::{DocumentElement, NarrationTrait};
13
14#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
17#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
18pub enum ParagraphFormatting {
19    Block,
20    Inline,
21    Collapsed,
22}
23
24#[derive(Debug)]
25pub struct LogicalParagraph<State: CheckingState> {
26    pub kind: ParagraphKind,
27    pub uri: DocumentElementURI,
28    pub formatting: ParagraphFormatting,
29    pub title: Option<DocumentRange>,
30    pub range: DocumentRange,
31    pub styles: Box<[Name]>,
32    pub children: State::Seq<DocumentElement<State>>,
33    pub fors: VecMap<SymbolURI, Option<Term>>,
34}
35
36crate::serde_impl! {
37    struct LogicalParagraph[kind,uri,formatting,title,range,styles,children,fors]
38}
39
40impl NarrationTrait for LogicalParagraph<Checked> {
41    #[inline]
42    fn children(&self) -> &[DocumentElement<Checked>] {
43        &self.children
44    }
45    #[inline]
46    fn from_element(e: &DocumentElement<Checked>) -> Option<&Self>
47    where
48        Self: Sized,
49    {
50        if let DocumentElement::Paragraph(e) = e {
51            Some(e)
52        } else {
53            None
54        }
55    }
56}
57
58#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
60#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
61#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
62#[non_exhaustive]
63pub enum ParagraphKind {
64    Definition,
65    Assertion,
66    Paragraph,
67    Proof,
68    SubProof,
69    Example,
70}
71
72impl ParagraphKind {
73    const DEF: &str = FTMLKey::Definition.attr_name();
74    const ASS: &str = FTMLKey::Assertion.attr_name();
75    const PAR: &str = FTMLKey::Paragraph.attr_name();
76    const PRO: &str = FTMLKey::Proof.attr_name();
77    const SUB: &str = FTMLKey::SubProof.attr_name();
78    #[must_use]
79    pub fn from_ftml(s: &str) -> Option<Self> {
80        Some(match s {
81            Self::DEF => Self::Definition,
82            Self::ASS => Self::Assertion,
83            Self::PAR => Self::Paragraph,
84            Self::PRO => Self::Proof,
85            Self::SUB => Self::SubProof,
86            _ => return None,
87        })
88    }
89    #[must_use]
90    pub fn is_definition_like(&self, styles: &[Name]) -> bool {
91        match &self {
92            Self::Definition | Self::Assertion => true,
93            _ => styles
94                .iter()
95                .any(|s| s.first_name().as_ref() == "symdoc" || s.first_name().as_ref() == "decl"),
96        }
97    }
98    #[cfg(feature = "rdf")]
99    #[must_use]
100    #[allow(clippy::wildcard_imports)]
101    pub const fn rdf_type(&self) -> crate::rdf::NamedNodeRef {
102        use crate::rdf::ontologies::ulo2::*;
103        match self {
104            Self::Definition => DEFINITION,
105            Self::Assertion => PROPOSITION,
106            Self::Paragraph => PARA,
107            Self::Proof => PROOF,
108            Self::SubProof => SUBPROOF,
109            Self::Example => EXAMPLE,
110        }
111    }
112
113    #[must_use]
114    pub const fn as_str(self) -> &'static str {
115        match self {
116            Self::Definition => "definition",
117            Self::Assertion => "assertion",
118            Self::Paragraph => "paragraph",
119            Self::Proof => "proof",
120            Self::SubProof => "subproof",
121            Self::Example => "example",
122        }
123    }
124
125    #[must_use]
126    pub const fn as_display_str(self) -> &'static str {
127        match self {
128            Self::Definition => "Definition",
129            Self::Assertion => "Assertion",
130            Self::Paragraph => "Paragraph",
131            Self::Proof => "Proof",
132            Self::SubProof => "Subproof",
133            Self::Example => "Example",
134        }
135    }
136}
137impl Display for ParagraphKind {
138    #[inline]
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        f.write_str(self.as_display_str())
141    }
142}
143impl FromStr for ParagraphKind {
144    type Err = ();
145    #[inline]
146    fn from_str(s: &str) -> Result<Self, Self::Err> {
147        match s.trim() {
148            "definition" => Ok(Self::Definition),
149            "assertion" => Ok(Self::Assertion),
150            "paragraph" => Ok(Self::Paragraph),
151            "proof" => Ok(Self::Proof),
152            "subproof" => Ok(Self::SubProof),
153            "example" => Ok(Self::Example),
154            _ => Err(()),
155        }
156    }
157}