Skip to main content

ironmark/
lib.rs

1#![deny(clippy::undocumented_unsafe_blocks)]
2
3//! # ironmark
4//!
5//! A fast, CommonMark 0.31.2 compliant Markdown-to-HTML parser with extensions.
6//!
7//! ## Usage
8//!
9//! ```
10//! use ironmark::{parse, ParseOptions};
11//!
12//! // With defaults (all extensions enabled)
13//! let html = parse("# Hello, **world**!", &ParseOptions::default());
14//!
15//! // Disable specific extensions
16//! let opts = ParseOptions {
17//!     enable_strikethrough: false,
18//!     enable_tables: false,
19//!     ..Default::default()
20//! };
21//! let html = parse("Plain CommonMark only.", &opts);
22//! ```
23//!
24//! ## Extensions
25//!
26//! All extensions are enabled by default via [`ParseOptions`]:
27//!
28//! | Syntax | HTML | Option |
29//! |---|---|---|
30//! | `~~text~~` | `<del>` | `enable_strikethrough` |
31//! | `==text==` | `<mark>` | `enable_highlight` |
32//! | `++text++` | `<u>` | `enable_underline` |
33//! | `\| table \|` | `<table>` | `enable_tables` |
34//! | `- [x] task` | checkbox | `enable_task_lists` |
35//! | bare URLs | `<a>` | `enable_autolink` |
36//! | newlines | `<br />` | `hard_breaks` |
37
38pub mod ast;
39mod block;
40mod entities;
41mod html;
42mod inline;
43mod render;
44
45pub use ast::{Block, ListKind, TableAlignment, TableData};
46pub use block::{parse, parse_to_ast};
47
48#[inline(always)]
49pub(crate) fn is_ascii_punctuation(b: u8) -> bool {
50    matches!(b, b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~')
51}
52
53#[inline(always)]
54pub(crate) fn utf8_char_len(first: u8) -> usize {
55    if first < 0x80 {
56        1
57    } else if first < 0xE0 {
58        2
59    } else if first < 0xF0 {
60        3
61    } else {
62        4
63    }
64}
65
66/// Options for customizing Markdown parsing behavior.
67pub struct ParseOptions {
68    /// When `true`, every newline inside a paragraph becomes a hard line break (`<br />`),
69    /// similar to GitHub Flavored Markdown. Default: `true`.
70    pub hard_breaks: bool,
71    /// Enable `==highlight==` syntax → `<mark>`. Default: `true`.
72    pub enable_highlight: bool,
73    /// Enable `~~strikethrough~~` syntax → `<del>`. Default: `true`.
74    pub enable_strikethrough: bool,
75    /// Enable `++underline++` syntax → `<u>`. Default: `true`.
76    pub enable_underline: bool,
77    /// Enable pipe table syntax. Default: `true`.
78    pub enable_tables: bool,
79    /// Automatically detect bare URLs (`https://...`) and emails (`user@example.com`)
80    /// and wrap them in `<a>` tags. Default: `true`.
81    pub enable_autolink: bool,
82    /// Enable GitHub-style task lists (`- [ ] unchecked`, `- [x] checked`)
83    /// in list items. Default: `true`.
84    pub enable_task_lists: bool,
85}
86
87impl Default for ParseOptions {
88    fn default() -> Self {
89        Self {
90            hard_breaks: true,
91            enable_highlight: true,
92            enable_strikethrough: true,
93            enable_underline: true,
94            enable_tables: true,
95            enable_autolink: true,
96            enable_task_lists: true,
97        }
98    }
99}