#![cfg_attr(rustbuild, feature(staged_api, rustc_private))]
#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(not(feature = "simd"), forbid(unsafe_code))]
#![warn(missing_debug_implementations)]
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "html")]
pub mod html;
pub mod utils;
mod entities;
mod firstpass;
mod linklabel;
mod parse;
mod puncttable;
mod scanners;
mod strings;
mod tree;
use std::fmt::Display;
pub use crate::parse::{
BrokenLink, BrokenLinkCallback, DefaultBrokenLinkCallback, OffsetIter, Parser, RefDefs,
};
pub use crate::strings::{CowStr, InlineStr};
pub use crate::utils::*;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CodeBlockKind<'a> {
Indented,
#[cfg_attr(feature = "serde", serde(borrow))]
Fenced(CowStr<'a>),
}
impl<'a> CodeBlockKind<'a> {
pub fn is_indented(&self) -> bool {
matches!(*self, CodeBlockKind::Indented)
}
pub fn is_fenced(&self) -> bool {
matches!(*self, CodeBlockKind::Fenced(_))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum BlockQuoteKind {
Note,
Tip,
Important,
Warning,
Caution,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MetadataBlockKind {
YamlStyle,
PlusesStyle,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Tag<'a> {
Paragraph,
Heading {
level: HeadingLevel,
id: Option<CowStr<'a>>,
classes: Vec<CowStr<'a>>,
attrs: Vec<(CowStr<'a>, Option<CowStr<'a>>)>,
},
BlockQuote(Option<BlockQuoteKind>),
CodeBlock(CodeBlockKind<'a>),
HtmlBlock,
List(Option<u64>), Item,
#[cfg_attr(feature = "serde", serde(borrow))]
FootnoteDefinition(CowStr<'a>),
Table(Vec<Alignment>),
TableHead,
TableRow,
TableCell,
Emphasis,
Strong,
Strikethrough,
Link {
link_type: LinkType,
dest_url: CowStr<'a>,
title: CowStr<'a>,
id: CowStr<'a>,
},
Image {
link_type: LinkType,
dest_url: CowStr<'a>,
title: CowStr<'a>,
id: CowStr<'a>,
},
MetadataBlock(MetadataBlockKind),
}
impl<'a> Tag<'a> {
pub fn to_end(&self) -> TagEnd {
match self {
Tag::Paragraph => TagEnd::Paragraph,
Tag::Heading { level, .. } => TagEnd::Heading(*level),
Tag::BlockQuote(_) => TagEnd::BlockQuote,
Tag::CodeBlock(_) => TagEnd::CodeBlock,
Tag::HtmlBlock => TagEnd::HtmlBlock,
Tag::List(number) => TagEnd::List(number.is_some()),
Tag::Item => TagEnd::Item,
Tag::FootnoteDefinition(_) => TagEnd::FootnoteDefinition,
Tag::Table(_) => TagEnd::Table,
Tag::TableHead => TagEnd::TableHead,
Tag::TableRow => TagEnd::TableRow,
Tag::TableCell => TagEnd::TableCell,
Tag::Emphasis => TagEnd::Emphasis,
Tag::Strong => TagEnd::Strong,
Tag::Strikethrough => TagEnd::Strikethrough,
Tag::Link { .. } => TagEnd::Link,
Tag::Image { .. } => TagEnd::Image,
Tag::MetadataBlock(kind) => TagEnd::MetadataBlock(*kind),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TagEnd {
Paragraph,
Heading(HeadingLevel),
BlockQuote,
CodeBlock,
HtmlBlock,
List(bool),
Item,
FootnoteDefinition,
Table,
TableHead,
TableRow,
TableCell,
Emphasis,
Strong,
Strikethrough,
Link,
Image,
MetadataBlock(MetadataBlockKind),
}
impl<'a> From<Tag<'a>> for TagEnd {
fn from(value: Tag) -> Self {
value.to_end()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum HeadingLevel {
H1 = 1,
H2,
H3,
H4,
H5,
H6,
}
impl Display for HeadingLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::H1 => write!(f, "h1"),
Self::H2 => write!(f, "h2"),
Self::H3 => write!(f, "h3"),
Self::H4 => write!(f, "h4"),
Self::H5 => write!(f, "h5"),
Self::H6 => write!(f, "h6"),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct InvalidHeadingLevel(usize);
impl TryFrom<usize> for HeadingLevel {
type Error = InvalidHeadingLevel;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::H1),
2 => Ok(Self::H2),
3 => Ok(Self::H3),
4 => Ok(Self::H4),
5 => Ok(Self::H5),
6 => Ok(Self::H6),
_ => Err(InvalidHeadingLevel(value)),
}
}
}
#[derive(Clone, Debug, PartialEq, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum LinkType {
Inline,
Reference,
ReferenceUnknown,
Collapsed,
CollapsedUnknown,
Shortcut,
ShortcutUnknown,
Autolink,
Email,
}
impl LinkType {
fn to_unknown(self) -> Self {
match self {
LinkType::Reference => LinkType::ReferenceUnknown,
LinkType::Collapsed => LinkType::CollapsedUnknown,
LinkType::Shortcut => LinkType::ShortcutUnknown,
_ => unreachable!(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Event<'a> {
#[cfg_attr(feature = "serde", serde(borrow))]
Start(Tag<'a>),
End(TagEnd),
#[cfg_attr(feature = "serde", serde(borrow))]
Text(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
Code(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
InlineMath(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
DisplayMath(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
Html(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
InlineHtml(CowStr<'a>),
#[cfg_attr(feature = "serde", serde(borrow))]
FootnoteReference(CowStr<'a>),
SoftBreak,
HardBreak,
Rule,
TaskListMarker(bool),
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Alignment {
None,
Left,
Center,
Right,
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Options: u32 {
const ENABLE_TABLES = 1 << 1;
const ENABLE_FOOTNOTES = 1 << 2;
const ENABLE_STRIKETHROUGH = 1 << 3;
const ENABLE_TASKLISTS = 1 << 4;
const ENABLE_SMART_PUNCTUATION = 1 << 5;
const ENABLE_HEADING_ATTRIBUTES = 1 << 6;
const ENABLE_YAML_STYLE_METADATA_BLOCKS = 1 << 7;
const ENABLE_PLUSES_DELIMITED_METADATA_BLOCKS = 1 << 8;
const ENABLE_OLD_FOOTNOTES = (1 << 9) | (1 << 2);
const ENABLE_MATH = 1 << 10;
const ENABLE_GFM = 1 << 11;
}
}
impl Options {
pub(crate) fn has_gfm_footnotes(&self) -> bool {
self.contains(Options::ENABLE_FOOTNOTES) && !self.contains(Options::ENABLE_OLD_FOOTNOTES)
}
}