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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
use crate::document::Src;
/// Defines overrides for the element types (or _tags_) inferred from special
/// inline elements and code blocks.
#[non_exhaustive]
#[derive(Debug, Default, Clone)]
pub struct SpecialTagConfig<'src> {
/// Tag name for `</ ... />`. Defaults to `em`.
pub emphasis: Option<Src<'src>>,
/// Tag name for `<# ... #>`. Defaults to `strong`.
pub strong: Option<Src<'src>>,
/// Tag name for `<_ ... _>`. Defaults to `u`.
pub underline: Option<Src<'src>>,
/// Tag name for `<~ ... ~>`. Defaults to `s`.
pub strike: Option<Src<'src>>,
/// Tag name for `<" ... ">`. Defaults to `q`.
pub quote: Option<Src<'src>>,
/// Tag name for ``<` ... `>``. Defaults to `code`.
pub code: Option<Src<'src>>,
/// Code blocks (denoted with ```` ``` ````) will use the same tag as inline code,
/// wrapped in the tag provided by this field. Defaults to `pre`.
pub code_block_container: Option<Src<'src>>,
}
/// Configuration options for converting a MinTyML document.
#[non_exhaustive]
#[derive(Debug, Default, Clone)]
pub struct OutputConfig<'src> {
/// If `Some(tab)`, `tab` will be inserted for each indentation level.
/// The string should only contain whitespace in order to produce valid HTML.
/// If `None`, the output will not automatically insert indentation or line breaks.
pub indent: Option<Src<'src>>,
/// Whether the output should be in XHTML5 rather than HTML.
/// Defaults to `false`.
pub xml: Option<bool>,
/// Overrides for the tags that correspond to each kind of special element.
pub special_tags: SpecialTagConfig<'src>,
/// Whether the output should be a complete, valid HTML page. Defaults to `false`.
///
/// See the documentation for [OutputConfig::lang] for semantics.
pub complete_page: Option<bool>,
/// If provided, this value will be assigned to the `lang` attribute of each top-level element.
///
/// This is most useful when `complete_page` is enabled so that the root element has a `lang` attribute.
pub lang: Option<Src<'src>>,
}
impl<'src> OutputConfig<'src> {
/// Instantiates with default values for all options.
pub fn new() -> Self {
Self::default()
}
/// Convenience method for mutating `self` in the same expression where it was created.
///
/// # Example
/// ```
/// # use mintyml::OutputConfig;
/// let config = OutputConfig::new()
/// .update(|config| config.indent = Some(" ".into()))
/// .update(|config| config.xml = Some(true));
///
/// assert_eq!(config.indent.as_deref(), Some(" "));
/// assert_eq!(config.xml, Some(true));
/// ```
pub fn update(mut self, f: impl FnOnce(&mut Self)) -> Self {
f(&mut self);
self
}
/// Sets the string `tab` to insert for each indentation level of the output.
/// The string should only contain whitespace in order to produce valid HTML.
/// Setting this value enables automatic line breaks in the output.
///
/// # Example
/// ## Indent with spaces
///
/// ```
/// # use mintyml::OutputConfig;
/// let out = mintyml::convert(r#"
/// {
/// Hello, world!
/// }
/// "#, OutputConfig::new().indent(" ")).unwrap();
///
/// assert_eq!(out, "\
/// <div>
/// <p>Hello, world!</p>
/// </div>
/// ");
/// ```
///
/// ## Indent with tabs
///
/// ```
/// # use mintyml::OutputConfig;
/// let out = mintyml::convert(r#"
/// {
/// Hello, world!
/// }
/// "#, OutputConfig::new().indent("\t")).unwrap();
///
/// assert_eq!(out, "\
/// <div>
/// \t<p>Hello, world!</p>
/// </div>
/// ");
/// ```
pub fn indent(self, tab: impl Into<Src<'src>>) -> Self {
self.update(|c| c.indent = Some(tab.into()))
}
/// Specifies whether the output document should be in XHTML5 rather than HTML.
///
/// This is useful when the output needs to be read by an XML parser.
pub fn xml(self, enabled: bool) -> Self {
self.update(|c| c.xml = Some(enabled))
}
/// Overrides the tag used for `</ ... />`. Defaults to `em`.
pub fn emphasis_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.emphasis = Some(tag.into()))
}
/// Overrides the tag used for `<# ... #>`. Defaults to `strong`.
pub fn strong_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.strong = Some(tag.into()))
}
/// Overrides the tag used for `<_ ... _>`. Defaults to `u`.
pub fn underline_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.underline = Some(tag.into()))
}
/// Overrides the tag used for `<~ ... ~>`. Defaults to `s`.
pub fn strike_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.strike = Some(tag.into()))
}
/// Overrides the tag used for `<" ... ">`. Defaults to `q`.
pub fn quote_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.quote = Some(tag.into()))
}
/// Overrides the tag used for ``<` ... `>``. Defaults to `code`.
pub fn code_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.code = Some(tag.into()))
}
/// Code blocks (denoted with ```` ``` ````) will use the same tag as inline code,
/// wrapped in the tag provided by this call. Defaults to `pre`.
pub fn code_block_container_tag(self, tag: impl Into<Src<'src>>) -> Self {
self.update(|c| c.special_tags.code_block_container = Some(tag.into()))
}
/// Whether the output should be a complete, valid HTML page. Defaults to `false`.
///
/// If enabled, the page will be automatically wrapped in `<html>` tags if one is not present.
/// If a `<body>` element exists at the top level, all top-level elements will be placed directly within the
/// `<html>` element.
/// Otherwise, all elements except those that belong in a `<head>` are placed in a `<body>` element.
/// The remaining elements will be merged into a `<head>` element.
///
/// If disabled, the document structure will remain unchanged.
pub fn complete_page(self, enabled: bool) -> Self {
self.update(|c| c.complete_page = enabled.into())
}
/// If provided, this value will be assigned to the `lang` attribute of each top-level element.
///
/// This is most useful when `complete_page` is enabled so that the root element has a `lang` attribute.
pub fn lang(self, lang: impl Into<Src<'src>>) -> Self {
self.update(|c| c.lang = lang.into().into())
}
}