Skip to main content

jotdown/
lib.rs

1//! A pull parser for [Djot](https://djot.net).
2//!
3//! The main entry is through [`Parser`] which constructs an [`Iterator`] of [`Event`]s. The events
4//! can then be processed before rendering them via the [`Render`] trait. This crate provides an
5//! [`html`] module that implements an HTML renderer.
6//!
7//! # Feature flags
8//!
9//! - `html` (default): build the [HTML renderer][html::Renderer],
10//! - `cli`: build a CLI binary that renders to HTML.
11//!
12//! # Examples
13//!
14//! Generate HTML from Djot input:
15//!
16//! ```
17//! # #[cfg(feature = "html")]
18//! # {
19//! let djot_input = "hello *world*!";
20//! let events = jotdown::Parser::new(djot_input);
21//! let html = jotdown::html::render_to_string(events);
22//! assert_eq!(html, "<p>hello <strong>world</strong>!</p>\n");
23//! # }
24//! ```
25//!
26//! Apply some filter to a specific type of element:
27//!
28//! ```
29//! # #[cfg(feature = "html")]
30//! # {
31//! # use jotdown::Event;
32//! # use jotdown::Container::Link;
33//! let events =
34//!     jotdown::Parser::new("a [link](https://example.com)").map(|e| match e {
35//!         Event::Start(Link(dst, ty), attrs) => {
36//!             Event::Start(Link(dst.replace(".com", ".net").into(), ty), attrs)
37//!         }
38//!         e => e,
39//!     });
40//! let html = jotdown::html::render_to_string(events);
41//! assert_eq!(html, "<p>a <a href=\"https://example.net\">link</a></p>\n");
42//! # }
43//! ```
44
45#[cfg(feature = "html")]
46pub mod html;
47
48mod attr;
49mod block;
50mod inline;
51mod lex;
52
53pub use attr::AttributeKind;
54pub use attr::AttributeValue;
55pub use attr::AttributeValueParts;
56pub use attr::Attributes;
57pub use attr::ParseAttributesError;
58
59type CowStr<'s> = std::borrow::Cow<'s, str>;
60
61/// A trait for rendering [`Event`]s to an output format.
62///
63/// The output can be written to either a [`std::fmt::Write`] or a [`std::io::Write`] object.
64///
65/// # Examples
66///
67/// Push to a [`String`] (implements [`std::fmt::Write`]):
68///
69/// ```
70/// # #[cfg(feature = "html")]
71/// # {
72/// # use jotdown::Render;
73/// # let events = std::iter::empty();
74/// let mut output = String::new();
75/// let mut renderer = jotdown::html::Renderer::default();
76/// renderer.push_events(events, &mut output);
77/// # }
78/// ```
79///
80/// Write to standard output with buffering ([`std::io::Stdout`] implements [`std::io::Write`]):
81///
82/// ```
83/// # #[cfg(feature = "html")]
84/// # {
85/// # use jotdown::Render;
86/// # let events = std::iter::empty();
87/// let mut out = std::io::BufWriter::new(std::io::stdout());
88/// let mut renderer = jotdown::html::Renderer::default();
89/// renderer.write_events(events, &mut out).unwrap();
90/// # }
91/// ```
92pub trait Render<'s> {
93    /// Push a single [`Event`] to a unicode-accepting buffer or stream.
94    fn push_event<W>(&mut self, event: Event<'s>, out: W) -> std::fmt::Result
95    where
96        W: std::fmt::Write;
97
98    /// Write a single [`Event`] to a byte sink, encoded as UTF-8.
99    ///
100    /// NOTE: This performs many small writes, so IO writes should be buffered with e.g.
101    /// [`std::io::BufWriter`].
102    fn write_event<W>(&mut self, event: Event<'s>, out: W) -> std::io::Result<()>
103    where
104        W: std::io::Write,
105    {
106        struct WriteAdapter<T: std::io::Write> {
107            inner: T,
108            error: std::io::Result<()>,
109        }
110
111        impl<T: std::io::Write> std::fmt::Write for WriteAdapter<T> {
112            fn write_str(&mut self, s: &str) -> std::fmt::Result {
113                self.inner.write_all(s.as_bytes()).map_err(|e| {
114                    self.error = Err(e);
115                    std::fmt::Error
116                })
117            }
118        }
119
120        let mut out = WriteAdapter {
121            inner: out,
122            error: Ok(()),
123        };
124
125        self.push_event(event, &mut out)
126            .map_err(|_| match out.error {
127                Err(e) => e,
128                _ => std::io::Error::other("formatter error"),
129            })
130    }
131
132    /// Push [`Event`]s to a unicode-accepting buffer or stream.
133    fn push_events<I, W>(&mut self, mut events: I, mut out: W) -> std::fmt::Result
134    where
135        I: Iterator<Item = Event<'s>>,
136        W: std::fmt::Write,
137    {
138        events.try_for_each(|e| self.push_event(e, &mut out))
139    }
140
141    /// Write [`Event`]s to a byte sink, encoded as UTF-8.
142    ///
143    /// NOTE: This performs many small writes, so IO writes should be buffered with e.g.
144    /// [`std::io::BufWriter`].
145    fn write_events<I, W>(&mut self, mut events: I, mut out: W) -> std::io::Result<()>
146    where
147        I: Iterator<Item = Event<'s>>,
148        W: std::io::Write,
149    {
150        events.try_for_each(|e| self.write_event(e, &mut out))
151    }
152}
153
154/// A Djot event.
155///
156/// A Djot document is represented by a sequence of events. An element may consist of one or
157/// multiple events. [`Container`] elements are represented by a [`Event::Start`] followed by
158/// events representing its content, and finally an [`Event::End`]. Atomic elements without any
159/// inside elements are represented by a single event.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum Event<'s> {
162    /// Start of a container.
163    ///
164    /// Always paired with a matching [`Event::End`].
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// # use jotdown::*;
170    /// let src = concat!(
171    ///     "{#a}\n",
172    ///     "[word]{#b}\n",
173    /// );
174    /// let events: Vec<_> = Parser::new(src).collect();
175    /// assert_eq!(
176    ///     &events,
177    ///     &[
178    ///         Event::Start(Container::Document, Attributes::new()),
179    ///         Event::Start(
180    ///             Container::Paragraph,
181    ///             [(AttributeKind::Id, "a".into())].into_iter().collect(),
182    ///         ),
183    ///         Event::Start(
184    ///             Container::Span,
185    ///             [(AttributeKind::Id, "b".into())].into_iter().collect(),
186    ///         ),
187    ///         Event::Str("word".into()),
188    ///         Event::End(Container::Span),
189    ///         Event::End(Container::Paragraph),
190    ///         Event::End(Container::Document),
191    ///     ],
192    /// );
193    /// let html = "<p id=\"a\"><span id=\"b\">word</span></p>\n";
194    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
195    /// ```
196    Start(Container<'s>, Attributes<'s>),
197    /// End of a container.
198    ///
199    /// Always paired with a matching [`Event::Start`].
200    End(Container<'s>),
201    /// A string object, text only.
202    ///
203    /// The strings from the parser will always be borrowed, but users may replace them with owned
204    /// variants before rendering.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// # use jotdown::*;
210    /// let src = "str";
211    /// let events: Vec<_> = Parser::new(src).collect();
212    /// assert_eq!(
213    ///     &events,
214    ///     &[
215    ///         Event::Start(Container::Document, Attributes::new()),
216    ///         Event::Start(Container::Paragraph, Attributes::new()),
217    ///         Event::Str("str".into()),
218    ///         Event::End(Container::Paragraph),
219    ///         Event::End(Container::Document),
220    ///     ],
221    /// );
222    /// let html = "<p>str</p>\n";
223    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
224    /// ```
225    Str(CowStr<'s>),
226    /// A footnote reference.
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// # use jotdown::*;
232    /// let src = "txt[^nb].";
233    /// let events: Vec<_> = Parser::new(src).collect();
234    /// assert_eq!(
235    ///     &events,
236    ///     &[
237    ///         Event::Start(Container::Document, Attributes::new()),
238    ///         Event::Start(Container::Paragraph, Attributes::new()),
239    ///         Event::Str("txt".into()),
240    ///         Event::FootnoteReference("nb".into()),
241    ///         Event::Str(".".into()),
242    ///         Event::End(Container::Paragraph),
243    ///         Event::End(Container::Document),
244    ///     ],
245    /// );
246    /// let html = concat!(
247    ///     "<p>txt<a id=\"fnref1\" href=\"#fn1\" role=\"doc-noteref\"><sup>1</sup></a>.</p>\n",
248    ///     "<section role=\"doc-endnotes\">\n",
249    ///     "<hr>\n",
250    ///     "<ol>\n",
251    ///     "<li id=\"fn1\">\n",
252    ///     "<p><a href=\"#fnref1\" role=\"doc-backlink\">↩\u{fe0e}</a></p>\n",
253    ///     "</li>\n",
254    ///     "</ol>\n",
255    ///     "</section>\n",
256    /// );
257    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
258    /// ```
259    FootnoteReference(CowStr<'s>),
260    /// A symbol, by default rendered literally but may be treated specially.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// # use jotdown::*;
266    /// let src = "a :sym:";
267    /// let events: Vec<_> = Parser::new(src).collect();
268    /// assert_eq!(
269    ///     &events,
270    ///     &[
271    ///         Event::Start(Container::Document, Attributes::new()),
272    ///         Event::Start(Container::Paragraph, Attributes::new()),
273    ///         Event::Str("a ".into()),
274    ///         Event::Symbol("sym".into()),
275    ///         Event::End(Container::Paragraph),
276    ///         Event::End(Container::Document),
277    ///     ],
278    /// );
279    /// let html = "<p>a :sym:</p>\n";
280    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
281    /// ```
282    Symbol(CowStr<'s>),
283    /// Left single quotation mark.
284    ///
285    /// # Examples
286    ///
287    /// ```
288    /// # use jotdown::*;
289    /// let src = r#"'quote'"#;
290    /// let events: Vec<_> = Parser::new(src).collect();
291    /// assert_eq!(
292    ///     &events,
293    ///     &[
294    ///         Event::Start(Container::Document, Attributes::new()),
295    ///         Event::Start(Container::Paragraph, Attributes::new()),
296    ///         Event::LeftSingleQuote,
297    ///         Event::Str("quote".into()),
298    ///         Event::RightSingleQuote,
299    ///         Event::End(Container::Paragraph),
300    ///         Event::End(Container::Document),
301    ///     ],
302    /// );
303    /// let html = "<p>‘quote’</p>\n";
304    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
305    /// ```
306    LeftSingleQuote,
307    /// Right single quotation mark.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// # use jotdown::*;
313    /// let src = r#"'}Tis Socrates'"#;
314    /// let events: Vec<_> = Parser::new(src).collect();
315    /// assert_eq!(
316    ///     &events,
317    ///     &[
318    ///         Event::Start(Container::Document, Attributes::new()),
319    ///         Event::Start(Container::Paragraph, Attributes::new()),
320    ///         Event::RightSingleQuote,
321    ///         Event::Str("Tis Socrates".into()),
322    ///         Event::RightSingleQuote,
323    ///         Event::End(Container::Paragraph),
324    ///         Event::End(Container::Document),
325    ///     ],
326    /// );
327    /// let html = "<p>’Tis Socrates’</p>\n";
328    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
329    /// ```
330    RightSingleQuote,
331    /// Left single quotation mark.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// # use jotdown::*;
337    /// let src = r#""Hello," he said"#;
338    /// let events: Vec<_> = Parser::new(src).collect();
339    /// assert_eq!(
340    ///     &events,
341    ///     &[
342    ///         Event::Start(Container::Document, Attributes::new()),
343    ///         Event::Start(Container::Paragraph, Attributes::new()),
344    ///         Event::LeftDoubleQuote,
345    ///         Event::Str("Hello,".into()),
346    ///         Event::RightDoubleQuote,
347    ///         Event::Str(" he said".into()),
348    ///         Event::End(Container::Paragraph),
349    ///         Event::End(Container::Document),
350    ///     ],
351    /// );
352    /// let html = "<p>“Hello,” he said</p>\n";
353    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
354    /// ```
355    LeftDoubleQuote,
356    /// Right double quotation mark.
357    RightDoubleQuote,
358    /// A horizontal ellipsis, i.e. a set of three periods.
359    ///
360    /// # Examples
361    ///
362    /// ```
363    /// # use jotdown::*;
364    /// let src = "yes...";
365    /// let events: Vec<_> = Parser::new(src).collect();
366    /// assert_eq!(
367    ///     &events,
368    ///     &[
369    ///         Event::Start(Container::Document, Attributes::new()),
370    ///         Event::Start(Container::Paragraph, Attributes::new()),
371    ///         Event::Str("yes".into()),
372    ///         Event::Ellipsis,
373    ///         Event::End(Container::Paragraph),
374    ///         Event::End(Container::Document),
375    ///     ],
376    /// );
377    /// let html = "<p>yes…</p>\n";
378    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
379    /// ```
380    Ellipsis,
381    /// An en dash.
382    ///
383    /// # Examples
384    ///
385    /// ```
386    /// # use jotdown::*;
387    /// let src = "57--33";
388    /// let events: Vec<_> = Parser::new(src).collect();
389    /// assert_eq!(
390    ///     &events,
391    ///     &[
392    ///         Event::Start(Container::Document, Attributes::new()),
393    ///         Event::Start(Container::Paragraph, Attributes::new()),
394    ///         Event::Str("57".into()),
395    ///         Event::EnDash,
396    ///         Event::Str("33".into()),
397    ///         Event::End(Container::Paragraph),
398    ///         Event::End(Container::Document),
399    ///     ],
400    /// );
401    /// let html = "<p>57–33</p>\n";
402    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
403    /// ```
404    EnDash,
405    /// An em dash.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// # use jotdown::*;
411    /// let src = "oxen---and";
412    /// let events: Vec<_> = Parser::new(src).collect();
413    /// assert_eq!(
414    ///     &events,
415    ///     &[
416    ///         Event::Start(Container::Document, Attributes::new()),
417    ///         Event::Start(Container::Paragraph, Attributes::new()),
418    ///         Event::Str("oxen".into()),
419    ///         Event::EmDash,
420    ///         Event::Str("and".into()),
421    ///         Event::End(Container::Paragraph),
422    ///         Event::End(Container::Document),
423    ///     ],
424    /// );
425    /// let html = "<p>oxen—and</p>\n";
426    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
427    /// ```
428    EmDash,
429    /// A space that must not break a line.
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// # use jotdown::*;
435    /// let src = "no\\ break";
436    /// let events: Vec<_> = Parser::new(src).collect();
437    /// assert_eq!(
438    ///     &events,
439    ///     &[
440    ///         Event::Start(Container::Document, Attributes::new()),
441    ///         Event::Start(Container::Paragraph, Attributes::new()),
442    ///         Event::Str("no".into()),
443    ///         Event::Escape,
444    ///         Event::NonBreakingSpace,
445    ///         Event::Str("break".into()),
446    ///         Event::End(Container::Paragraph),
447    ///         Event::End(Container::Document),
448    ///     ],
449    /// );
450    /// let html = "<p>no&nbsp;break</p>\n";
451    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
452    /// ```
453    NonBreakingSpace,
454    /// A newline that may or may not break a line in the output.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// # use jotdown::*;
460    /// let src = concat!(
461    ///     "soft\n",
462    ///     "break\n",
463    /// );
464    /// let events: Vec<_> = Parser::new(src).collect();
465    /// assert_eq!(
466    ///     &events,
467    ///     &[
468    ///         Event::Start(Container::Document, Attributes::new()),
469    ///         Event::Start(Container::Paragraph, Attributes::new()),
470    ///         Event::Str("soft".into()),
471    ///         Event::Softbreak,
472    ///         Event::Str("break".into()),
473    ///         Event::End(Container::Paragraph),
474    ///         Event::End(Container::Document),
475    ///     ],
476    /// );
477    /// let html = concat!(
478    ///     "<p>soft\n",
479    ///     "break</p>\n",
480    /// );
481    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
482    /// ```
483    Softbreak,
484    /// A newline that must break a line in the output.
485    ///
486    /// # Examples
487    ///
488    /// ```
489    /// # use jotdown::*;
490    /// let src = concat!(
491    ///     "hard\\\n",
492    ///     "break\n",
493    /// );
494    /// let events: Vec<_> = Parser::new(src).collect();
495    /// assert_eq!(
496    ///     &events,
497    ///     &[
498    ///         Event::Start(Container::Document, Attributes::new()),
499    ///         Event::Start(Container::Paragraph, Attributes::new()),
500    ///         Event::Str("hard".into()),
501    ///         Event::Escape,
502    ///         Event::Hardbreak,
503    ///         Event::Str("break".into()),
504    ///         Event::End(Container::Paragraph),
505    ///         Event::End(Container::Document),
506    ///     ],
507    /// );
508    /// let html = concat!(
509    ///     "<p>hard<br>\n",
510    ///     "break</p>\n",
511    /// );
512    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
513    /// ```
514    Hardbreak,
515    /// An escape character, not visible in output.
516    ///
517    /// # Examples
518    ///
519    /// ```
520    /// # use jotdown::*;
521    /// let src = "\\*a\\*";
522    /// let events: Vec<_> = Parser::new(src).collect();
523    /// assert_eq!(
524    ///     &events,
525    ///     &[
526    ///         Event::Start(Container::Document, Attributes::new()),
527    ///         Event::Start(Container::Paragraph, Attributes::new()),
528    ///         Event::Escape,
529    ///         Event::Str("*a".into()),
530    ///         Event::Escape,
531    ///         Event::Str("*".into()),
532    ///         Event::End(Container::Paragraph),
533    ///         Event::End(Container::Document),
534    ///     ],
535    /// );
536    /// let html = "<p>*a*</p>\n";
537    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
538    /// ```
539    Escape,
540    /// A blank line, not visible in output.
541    ///
542    /// # Examples
543    ///
544    /// ```
545    /// # use jotdown::*;
546    /// let src = concat!(
547    ///     "para0\n",
548    ///     "\n",
549    ///     "para1\n",
550    /// );
551    /// let events: Vec<_> = Parser::new(src).collect();
552    /// assert_eq!(
553    ///     &events,
554    ///     &[
555    ///         Event::Start(Container::Document, Attributes::new()),
556    ///         Event::Start(Container::Paragraph, Attributes::new()),
557    ///         Event::Str("para0".into()),
558    ///         Event::End(Container::Paragraph),
559    ///         Event::Blankline,
560    ///         Event::Start(Container::Paragraph, Attributes::new()),
561    ///         Event::Str("para1".into()),
562    ///         Event::End(Container::Paragraph),
563    ///         Event::End(Container::Document),
564    ///     ],
565    /// );
566    /// let html = concat!(
567    ///     "<p>para0</p>\n",
568    ///     "<p>para1</p>\n",
569    /// );
570    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
571    /// ```
572    Blankline,
573    /// A thematic break, typically a horizontal rule.
574    ///
575    /// # Examples
576    ///
577    /// ```
578    /// # use jotdown::*;
579    /// let src = concat!(
580    ///     "para0\n",
581    ///     "\n",
582    ///     " * * * *\n",
583    ///     "para1\n",
584    ///     "\n",
585    ///     "{.c}\n",
586    ///     "----\n",
587    /// );
588    /// let events: Vec<_> = Parser::new(src).collect();
589    /// assert_eq!(
590    ///     &events,
591    ///     &[
592    ///         Event::Start(Container::Document, Attributes::new()),
593    ///         Event::Start(Container::Paragraph, Attributes::new()),
594    ///         Event::Str("para0".into()),
595    ///         Event::End(Container::Paragraph),
596    ///         Event::Blankline,
597    ///         Event::ThematicBreak(Attributes::new()),
598    ///         Event::Start(Container::Paragraph, Attributes::new()),
599    ///         Event::Str("para1".into()),
600    ///         Event::End(Container::Paragraph),
601    ///         Event::Blankline,
602    ///         Event::ThematicBreak(
603    ///             [(AttributeKind::Class, "c".into())]
604    ///                 .into_iter()
605    ///                 .collect(),
606    ///         ),
607    ///         Event::End(Container::Document),
608    ///     ],
609    /// );
610    /// let html = concat!(
611    ///     "<p>para0</p>\n",
612    ///     "<hr>\n",
613    ///     "<p>para1</p>\n",
614    ///     "<hr class=\"c\">\n",
615    /// );
616    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
617    /// ```
618    ThematicBreak(Attributes<'s>),
619    /// Dangling attributes not attached to anything.
620    ///
621    /// # Examples
622    ///
623    /// ```
624    /// # use jotdown::*;
625    /// let src = concat!(
626    ///     "{#a}\n",
627    ///     "\n",
628    ///     "inline {#b}\n",
629    ///     "\n",
630    ///     "{#c}\n",
631    /// );
632    /// let events: Vec<_> = Parser::new(src).collect();
633    /// assert_eq!(
634    ///     &events,
635    ///     &[
636    ///         Event::Start(Container::Document, Attributes::new()),
637    ///         Event::Attributes(
638    ///             [(AttributeKind::Id, "a".into())]
639    ///                 .into_iter()
640    ///                 .collect(),
641    ///         ),
642    ///         Event::Blankline,
643    ///         Event::Start(Container::Paragraph, Attributes::new()),
644    ///         Event::Str("inline ".into()),
645    ///         Event::Attributes(
646    ///             [(AttributeKind::Id, "b".into())]
647    ///                 .into_iter()
648    ///                 .collect(),
649    ///         ),
650    ///         Event::End(Container::Paragraph),
651    ///         Event::Blankline,
652    ///         Event::Attributes(
653    ///             [(AttributeKind::Id, "c".into())]
654    ///                 .into_iter()
655    ///                 .collect(),
656    ///         ),
657    ///         Event::End(Container::Document),
658    ///     ],
659    /// );
660    /// let html = concat!(
661    ///     "\n",
662    ///     "<p>inline </p>\n",
663    /// );
664    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
665    /// ```
666    Attributes(Attributes<'s>),
667}
668
669/// A container that may contain other elements.
670///
671/// There are three types of containers:
672///
673/// - inline, may only contain inline elements,
674/// - block leaf, may only contain inline elements,
675/// - block container, may contain any block-level elements.
676#[derive(Debug, Clone, PartialEq, Eq)]
677pub enum Container<'s> {
678    /// A document.
679    ///
680    /// Must appear exactly once at the start and end of the event stream.
681    ///
682    /// # Examples
683    ///
684    /// ```
685    /// # use jotdown::*;
686    /// let src = "";
687    /// let events: Vec<_> = Parser::new(src).collect();
688    /// assert_eq!(
689    ///     &events,
690    ///     &[
691    ///         Event::Start(Container::Document, Attributes::new()),
692    ///         Event::End(Container::Document),
693    ///     ],
694    /// );
695    /// ```
696    Document,
697    /// A blockquote element.
698    ///
699    /// # Examples
700    ///
701    /// ```
702    /// # use jotdown::*;
703    /// let src = concat!(
704    ///     "> a\n",
705    ///     "> b\n",
706    /// );
707    /// let events: Vec<_> = Parser::new(src).collect();
708    /// assert_eq!(
709    ///     &events,
710    ///     &[
711    ///         Event::Start(Container::Document, Attributes::new()),
712    ///         Event::Start(Container::Blockquote, Attributes::new()),
713    ///         Event::Start(Container::Paragraph, Attributes::new()),
714    ///         Event::Str("a".into()),
715    ///         Event::Softbreak,
716    ///         Event::Str("b".into()),
717    ///         Event::End(Container::Paragraph),
718    ///         Event::End(Container::Blockquote),
719    ///         Event::End(Container::Document),
720    ///     ],
721    /// );
722    /// let html = concat!(
723    ///     "<blockquote>\n",
724    ///     "<p>a\n",
725    ///     "b</p>\n",
726    ///     "</blockquote>\n",
727    /// );
728    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
729    /// ```
730    Blockquote,
731    /// A list.
732    ///
733    /// # Examples
734    ///
735    /// ```
736    /// # use jotdown::*;
737    /// let src = concat!(
738    ///     "- a\n",
739    ///     "\n",
740    ///     "- b\n",
741    /// );
742    /// let events: Vec<_> = Parser::new(src).collect();
743    /// assert_eq!(
744    ///     &events,
745    ///     &[
746    ///         Event::Start(Container::Document, Attributes::new()),
747    ///         Event::Start(
748    ///             Container::List {
749    ///                 kind: ListKind::Unordered(ListBulletType::Dash),
750    ///                 tight: false,
751    ///             },
752    ///             Attributes::new(),
753    ///         ),
754    ///         Event::Start(Container::ListItem, Attributes::new()),
755    ///         Event::Start(Container::Paragraph, Attributes::new()),
756    ///         Event::Str("a".into()),
757    ///         Event::End(Container::Paragraph),
758    ///         Event::Blankline,
759    ///         Event::End(Container::ListItem),
760    ///         Event::Start(Container::ListItem, Attributes::new()),
761    ///         Event::Start(Container::Paragraph, Attributes::new()),
762    ///         Event::Str("b".into()),
763    ///         Event::End(Container::Paragraph),
764    ///         Event::End(Container::ListItem),
765    ///         Event::End(Container::List {
766    ///             kind: ListKind::Unordered(ListBulletType::Dash),
767    ///             tight: false
768    ///         }),
769    ///         Event::End(Container::Document),
770    ///     ],
771    /// );
772    /// let html = concat!(
773    ///     "<ul>\n",
774    ///     "<li>\n",
775    ///     "<p>a</p>\n",
776    ///     "</li>\n",
777    ///     "<li>\n",
778    ///     "<p>b</p>\n",
779    ///     "</li>\n",
780    ///     "</ul>\n",
781    /// );
782    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
783    /// ```
784    List { kind: ListKind, tight: bool },
785    /// An item of a list
786    ///
787    /// # Examples
788    ///
789    /// ```
790    /// # use jotdown::*;
791    /// let src = "- a";
792    /// let events: Vec<_> = Parser::new(src).collect();
793    /// assert_eq!(
794    ///     &events,
795    ///     &[
796    ///         Event::Start(Container::Document, Attributes::new()),
797    ///         Event::Start(
798    ///             Container::List {
799    ///                 kind: ListKind::Unordered(ListBulletType::Dash),
800    ///                 tight: true,
801    ///             },
802    ///             Attributes::new(),
803    ///         ),
804    ///         Event::Start(Container::ListItem, Attributes::new()),
805    ///         Event::Start(Container::Paragraph, Attributes::new()),
806    ///         Event::Str("a".into()),
807    ///         Event::End(Container::Paragraph),
808    ///         Event::End(Container::ListItem),
809    ///         Event::End(Container::List {
810    ///             kind: ListKind::Unordered(ListBulletType::Dash),
811    ///             tight: true,
812    ///         }),
813    ///         Event::End(Container::Document),
814    ///     ],
815    /// );
816    /// let html = concat!(
817    ///     "<ul>\n",
818    ///     "<li>\n",
819    ///     "a\n",
820    ///     "</li>\n",
821    ///     "</ul>\n",
822    /// );
823    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
824    /// ```
825    ListItem,
826    /// An item of a task list, either checked or unchecked.
827    ///
828    /// # Examples
829    ///
830    /// ```
831    /// # use jotdown::*;
832    /// let src = "- [x] a";
833    /// let events: Vec<_> = Parser::new(src).collect();
834    /// assert_eq!(
835    ///     &events,
836    ///     &[
837    ///         Event::Start(Container::Document, Attributes::new()),
838    ///         Event::Start(
839    ///             Container::List {
840    ///                 kind: ListKind::Task(ListBulletType::Dash),
841    ///                 tight: true
842    ///             },
843    ///             Attributes::new(),
844    ///         ),
845    ///         Event::Start(
846    ///             Container::TaskListItem { checked: true },
847    ///             Attributes::new(),
848    ///         ),
849    ///         Event::Start(Container::Paragraph, Attributes::new()),
850    ///         Event::Str("a".into()),
851    ///         Event::End(Container::Paragraph),
852    ///         Event::End(Container::TaskListItem { checked: true }),
853    ///         Event::End(Container::List {
854    ///             kind: ListKind::Task(ListBulletType::Dash),
855    ///             tight: true,
856    ///         }),
857    ///         Event::End(Container::Document),
858    ///     ],
859    /// );
860    /// let html = concat!(
861    ///     "<ul class=\"task-list\">\n",
862    ///     "<li>\n",
863    ///     "<input disabled=\"\" type=\"checkbox\" checked=\"\"/>\n",
864    ///     "a\n",
865    ///     "</li>\n",
866    ///     "</ul>\n",
867    /// );
868    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
869    /// ```
870    TaskListItem { checked: bool },
871    /// A description list.
872    ///
873    /// # Examples
874    ///
875    /// ```
876    /// # use jotdown::*;
877    /// let src = concat!(
878    ///     ": orange\n",
879    ///     "\n",
880    ///     " citrus fruit\n",
881    ///     ": apple\n",
882    ///     "\n",
883    ///     " malus fruit\n",
884    /// );
885    /// let events: Vec<_> = Parser::new(src).collect();
886    /// assert_eq!(
887    ///     &events,
888    ///     &[
889    ///         Event::Start(Container::Document, Attributes::new()),
890    ///         Event::Start(Container::DescriptionList, Attributes::new()),
891    ///         Event::Start(Container::DescriptionTerm, Attributes::new()),
892    ///         Event::Str("orange".into()),
893    ///         Event::End(Container::DescriptionTerm),
894    ///         Event::Blankline,
895    ///         Event::Start(Container::DescriptionDetails, Attributes::new()),
896    ///         Event::Start(Container::Paragraph, Attributes::new()),
897    ///         Event::Str("citrus fruit".into()),
898    ///         Event::End(Container::Paragraph),
899    ///         Event::End(Container::DescriptionDetails),
900    ///         Event::Start(Container::DescriptionTerm, Attributes::new()),
901    ///         Event::Str("apple".into()),
902    ///         Event::End(Container::DescriptionTerm),
903    ///         Event::Blankline,
904    ///         Event::Start(Container::DescriptionDetails, Attributes::new()),
905    ///         Event::Start(Container::Paragraph, Attributes::new()),
906    ///         Event::Str("malus fruit".into()),
907    ///         Event::End(Container::Paragraph),
908    ///         Event::End(Container::DescriptionDetails),
909    ///         Event::End(Container::DescriptionList),
910    ///         Event::End(Container::Document),
911    ///     ],
912    /// );
913    /// let html = concat!(
914    ///     "<dl>\n",
915    ///     "<dt>orange</dt>\n",
916    ///     "<dd>\n",
917    ///     "<p>citrus fruit</p>\n",
918    ///     "</dd>\n",
919    ///     "<dt>apple</dt>\n",
920    ///     "<dd>\n",
921    ///     "<p>malus fruit</p>\n",
922    ///     "</dd>\n",
923    ///     "</dl>\n",
924    /// );
925    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
926    /// ```
927    DescriptionList,
928    /// Details describing a term within a description list.
929    DescriptionDetails,
930    /// A footnote definition.
931    ///
932    /// # Examples
933    ///
934    /// ```
935    /// # use jotdown::*;
936    /// let src = concat!(
937    ///     "txt[^nb]\n",
938    ///     "\n",
939    ///     "[^nb]: actually..\n",
940    /// );
941    /// let events: Vec<_> = Parser::new(src).collect();
942    /// assert_eq!(
943    ///     &events,
944    ///     &[
945    ///         Event::Start(Container::Document, Attributes::new()),
946    ///         Event::Start(Container::Paragraph, Attributes::new()),
947    ///         Event::Str("txt".into()),
948    ///         Event::FootnoteReference("nb".into()),
949    ///         Event::End(Container::Paragraph),
950    ///         Event::Blankline,
951    ///         Event::Start(
952    ///             Container::Footnote { label: "nb".into() },
953    ///             Attributes::new(),
954    ///         ),
955    ///         Event::Start(Container::Paragraph, Attributes::new()),
956    ///         Event::Str("actually..".into()),
957    ///         Event::End(Container::Paragraph),
958    ///         Event::End(Container::Footnote { label: "nb".into() }),
959    ///         Event::End(Container::Document),
960    ///     ],
961    /// );
962    /// let html = concat!(
963    ///     "<p>txt<a id=\"fnref1\" href=\"#fn1\" role=\"doc-noteref\"><sup>1</sup></a></p>\n",
964    ///     "<section role=\"doc-endnotes\">\n",
965    ///     "<hr>\n",
966    ///     "<ol>\n",
967    ///     "<li id=\"fn1\">\n",
968    ///     "<p>actually..<a href=\"#fnref1\" role=\"doc-backlink\">↩\u{fe0e}</a></p>\n",
969    ///     "</li>\n",
970    ///     "</ol>\n",
971    ///     "</section>\n",
972    /// );
973    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
974    /// ```
975    Footnote { label: CowStr<'s> },
976    /// A table element.
977    ///
978    /// # Examples
979    ///
980    /// ```
981    /// # use jotdown::*;
982    /// let src = concat!(
983    ///     "| a | b |\n",
984    ///     "|---|--:|\n",
985    ///     "| 1 | 2 |\n",
986    /// );
987    /// let events: Vec<_> = Parser::new(src).collect();
988    /// assert_eq!(
989    ///     &events,
990    ///     &[
991    ///         Event::Start(Container::Document, Attributes::new()),
992    ///         Event::Start(Container::Table, Attributes::new()),
993    ///         Event::Start(
994    ///             Container::TableRow { head: true },
995    ///             Attributes::new(),
996    ///         ),
997    ///         Event::Start(
998    ///             Container::TableCell {
999    ///                 alignment: Alignment::Unspecified,
1000    ///                 head: true
1001    ///             },
1002    ///             Attributes::new(),
1003    ///         ),
1004    ///         Event::Str("a".into()),
1005    ///         Event::End(Container::TableCell {
1006    ///             alignment: Alignment::Unspecified,
1007    ///             head: true,
1008    ///         }),
1009    ///         Event::Start(
1010    ///             Container::TableCell {
1011    ///                 alignment: Alignment::Right,
1012    ///                 head: true,
1013    ///             },
1014    ///             Attributes::new(),
1015    ///         ),
1016    ///         Event::Str("b".into()),
1017    ///         Event::End(Container::TableCell {
1018    ///             alignment: Alignment::Right,
1019    ///             head: true,
1020    ///         }),
1021    ///         Event::End(Container::TableRow { head: true } ),
1022    ///         Event::Start(
1023    ///             Container::TableRow { head: false },
1024    ///             Attributes::new(),
1025    ///         ),
1026    ///         Event::Start(
1027    ///             Container::TableCell {
1028    ///                 alignment: Alignment::Unspecified,
1029    ///                 head: false
1030    ///             },
1031    ///             Attributes::new(),
1032    ///         ),
1033    ///         Event::Str("1".into()),
1034    ///         Event::End(Container::TableCell {
1035    ///             alignment: Alignment::Unspecified,
1036    ///             head: false,
1037    ///         }),
1038    ///         Event::Start(
1039    ///             Container::TableCell {
1040    ///                 alignment: Alignment::Right,
1041    ///                 head: false,
1042    ///             },
1043    ///             Attributes::new(),
1044    ///         ),
1045    ///         Event::Str("2".into()),
1046    ///         Event::End(Container::TableCell {
1047    ///             alignment: Alignment::Right,
1048    ///             head: false,
1049    ///         }),
1050    ///         Event::End(Container::TableRow { head: false } ),
1051    ///         Event::End(Container::Table),
1052    ///         Event::End(Container::Document),
1053    ///     ],
1054    /// );
1055    /// let html = concat!(
1056    ///     "<table>\n",
1057    ///     "<tr>\n",
1058    ///     "<th>a</th>\n",
1059    ///     "<th style=\"text-align: right;\">b</th>\n",
1060    ///     "</tr>\n",
1061    ///     "<tr>\n",
1062    ///     "<td>1</td>\n",
1063    ///     "<td style=\"text-align: right;\">2</td>\n",
1064    ///     "</tr>\n",
1065    ///     "</table>\n",
1066    /// );
1067    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1068    /// ```
1069    Table,
1070    /// A row element of a table.
1071    TableRow { head: bool },
1072    /// A section belonging to a top level heading.
1073    ///
1074    /// # Examples
1075    ///
1076    /// ```
1077    /// # use jotdown::*;
1078    /// let src = concat!(
1079    ///     "# outer\n",
1080    ///     "\n",
1081    ///     "## inner\n",
1082    /// );
1083    /// let events: Vec<_> = Parser::new(src).collect();
1084    /// assert_eq!(
1085    ///     &events,
1086    ///     &[
1087    ///         Event::Start(Container::Document, Attributes::new()),
1088    ///         Event::Start(
1089    ///             Container::Section { id: "outer".into() },
1090    ///             Attributes::new(),
1091    ///         ),
1092    ///         Event::Start(
1093    ///             Container::Heading {
1094    ///                 level: 1,
1095    ///                 has_section: true,
1096    ///                 id: "outer".into(),
1097    ///             },
1098    ///             Attributes::new(),
1099    ///         ),
1100    ///         Event::Str("outer".into()),
1101    ///         Event::End(Container::Heading {
1102    ///             level: 1,
1103    ///             has_section: true,
1104    ///             id: "outer".into(),
1105    ///         }),
1106    ///         Event::Blankline,
1107    ///         Event::Start(
1108    ///             Container::Section { id: "inner".into() },
1109    ///             Attributes::new(),
1110    ///         ),
1111    ///         Event::Start(
1112    ///             Container::Heading {
1113    ///                 level: 2,
1114    ///                 has_section: true,
1115    ///                 id: "inner".into(),
1116    ///             },
1117    ///             Attributes::new(),
1118    ///         ),
1119    ///         Event::Str("inner".into()),
1120    ///         Event::End(Container::Heading {
1121    ///             level: 2,
1122    ///             has_section: true,
1123    ///             id: "inner".into(),
1124    ///         }),
1125    ///         Event::End(Container::Section { id: "inner".into() }),
1126    ///         Event::End(Container::Section { id: "outer".into() }),
1127    ///         Event::End(Container::Document),
1128    ///     ],
1129    /// );
1130    /// let html = concat!(
1131    ///     "<section id=\"outer\">\n",
1132    ///     "<h1>outer</h1>\n",
1133    ///     "<section id=\"inner\">\n",
1134    ///     "<h2>inner</h2>\n",
1135    ///     "</section>\n",
1136    ///     "</section>\n",
1137    /// );
1138    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1139    /// ```
1140    Section { id: CowStr<'s> },
1141    /// A block-level divider element.
1142    ///
1143    /// # Examples
1144    ///
1145    /// ```
1146    /// # use jotdown::*;
1147    /// let src = concat!(
1148    ///     "::: note\n",
1149    ///     "this is a note\n",
1150    ///     ":::\n",
1151    /// );
1152    /// let events: Vec<_> = Parser::new(src).collect();
1153    /// assert_eq!(
1154    ///     &events,
1155    ///     &[
1156    ///         Event::Start(Container::Document, Attributes::new()),
1157    ///         Event::Start(
1158    ///             Container::Div { class: "note".into() },
1159    ///             Attributes::new(),
1160    ///         ),
1161    ///         Event::Start(Container::Paragraph, Attributes::new()),
1162    ///         Event::Str("this is a note".into()),
1163    ///         Event::End(Container::Paragraph),
1164    ///         Event::End(Container::Div { class: "note".into() }),
1165    ///         Event::End(Container::Document),
1166    ///     ],
1167    /// );
1168    /// let html = concat!(
1169    ///     "<div class=\"note\">\n",
1170    ///     "<p>this is a note</p>\n",
1171    ///     "</div>\n",
1172    /// );
1173    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1174    /// ```
1175    Div { class: CowStr<'s> },
1176    /// A paragraph.
1177    Paragraph,
1178    /// A heading.
1179    ///
1180    /// # Examples
1181    ///
1182    /// ```
1183    /// # use jotdown::*;
1184    /// let src = "# heading";
1185    /// let events: Vec<_> = Parser::new(src).collect();
1186    /// assert_eq!(
1187    ///     &events,
1188    ///     &[
1189    ///         Event::Start(Container::Document, Attributes::new()),
1190    ///         Event::Start(
1191    ///             Container::Section { id: "heading".into() },
1192    ///             Attributes::new(),
1193    ///         ),
1194    ///         Event::Start(
1195    ///             Container::Heading {
1196    ///                 level: 1,
1197    ///                 has_section: true,
1198    ///                 id: "heading".into(),
1199    ///             },
1200    ///             Attributes::new(),
1201    ///         ),
1202    ///         Event::Str("heading".into()),
1203    ///         Event::End(Container::Heading {
1204    ///             level: 1,
1205    ///             has_section: true,
1206    ///             id: "heading".into(),
1207    ///         }),
1208    ///         Event::End(Container::Section { id: "heading".into() }),
1209    ///         Event::End(Container::Document),
1210    ///     ],
1211    /// );
1212    /// let html = concat!(
1213    ///     "<section id=\"heading\">\n",
1214    ///     "<h1>heading</h1>\n",
1215    ///     "</section>\n",
1216    /// );
1217    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1218    /// ```
1219    Heading {
1220        level: u16,
1221        has_section: bool,
1222        id: CowStr<'s>,
1223    },
1224    /// A cell element of row within a table.
1225    TableCell { alignment: Alignment, head: bool },
1226    /// A caption within a table.
1227    ///
1228    /// # Examples
1229    ///
1230    /// ```
1231    /// # use jotdown::*;
1232    /// let src = concat!(
1233    ///     "|a|\n",
1234    ///     "^ caption\n",
1235    /// );
1236    /// let events: Vec<_> = Parser::new(src).collect();
1237    /// assert_eq!(
1238    ///     &events,
1239    ///     &[
1240    ///         Event::Start(Container::Document, Attributes::new()),
1241    ///         Event::Start(Container::Table, Attributes::new()),
1242    ///         Event::Start(Container::Caption, Attributes::new()),
1243    ///         Event::Str("caption".into()),
1244    ///         Event::End(Container::Caption),
1245    ///         Event::Start(
1246    ///             Container::TableRow { head: false },
1247    ///             Attributes::new(),
1248    ///         ),
1249    ///         Event::Start(
1250    ///             Container::TableCell {
1251    ///                 alignment: Alignment::Unspecified,
1252    ///                 head: false
1253    ///             },
1254    ///             Attributes::new(),
1255    ///         ),
1256    ///         Event::Str("a".into()),
1257    ///         Event::End(Container::TableCell {
1258    ///             alignment: Alignment::Unspecified,
1259    ///             head: false,
1260    ///         }),
1261    ///         Event::End(Container::TableRow { head: false } ),
1262    ///         Event::End(Container::Table),
1263    ///         Event::End(Container::Document),
1264    ///     ],
1265    /// );
1266    /// let html = concat!(
1267    ///     "<table>\n",
1268    ///     "<caption>caption</caption>\n",
1269    ///     "<tr>\n",
1270    ///     "<td>a</td>\n",
1271    ///     "</tr>\n",
1272    ///     "</table>\n",
1273    /// );
1274    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1275    /// ```
1276    Caption,
1277    /// A term within a description list.
1278    DescriptionTerm,
1279    /// A link definition.
1280    ///
1281    /// # Examples
1282    ///
1283    /// ```
1284    /// # use jotdown::*;
1285    /// let src = "[label]: url";
1286    /// let events: Vec<_> = Parser::new(src).collect();
1287    /// assert_eq!(
1288    ///     &events,
1289    ///     &[
1290    ///         Event::Start(Container::Document, Attributes::new()),
1291    ///         Event::Start(
1292    ///             Container::LinkDefinition { label: "label".into() },
1293    ///             Attributes::new(),
1294    ///         ),
1295    ///         Event::Str("url".into()),
1296    ///         Event::End(Container::LinkDefinition { label: "label".into() }),
1297    ///         Event::End(Container::Document),
1298    ///     ],
1299    /// );
1300    /// let html = "\n";
1301    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1302    /// ```
1303    LinkDefinition { label: CowStr<'s> },
1304    /// A block with raw markup for a specific output format.
1305    ///
1306    /// # Examples
1307    ///
1308    /// ```
1309    /// # use jotdown::*;
1310    /// let src = concat!(
1311    ///     "```=html\n",
1312    ///     "<tag>x</tag>\n",
1313    ///     "```\n",
1314    /// );
1315    /// let events: Vec<_> = Parser::new(src).collect();
1316    /// assert_eq!(
1317    ///     &events,
1318    ///     &[
1319    ///         Event::Start(Container::Document, Attributes::new()),
1320    ///         Event::Start(
1321    ///             Container::RawBlock { format: "html".into() },
1322    ///             Attributes::new(),
1323    ///         ),
1324    ///         Event::Str("<tag>x</tag>".into()),
1325    ///         Event::End(Container::RawBlock { format: "html".into() }),
1326    ///         Event::End(Container::Document),
1327    ///     ],
1328    /// );
1329    /// let html = "<tag>x</tag>\n";
1330    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1331    /// ```
1332    RawBlock { format: CowStr<'s> },
1333    /// A block with code in a specific language.
1334    ///
1335    /// # Examples
1336    ///
1337    /// ```
1338    /// # use jotdown::*;
1339    /// let src = concat!(
1340    ///     "```html\n",
1341    ///     "<tag>x</tag>\n",
1342    ///     "```\n",
1343    /// );
1344    /// let events: Vec<_> = Parser::new(src).collect();
1345    /// assert_eq!(
1346    ///     &events,
1347    ///     &[
1348    ///         Event::Start(Container::Document, Attributes::new()),
1349    ///         Event::Start(
1350    ///             Container::CodeBlock { language: "html".into() },
1351    ///             Attributes::new(),
1352    ///         ),
1353    ///         Event::Str("<tag>x</tag>\n".into()),
1354    ///         Event::End(Container::CodeBlock { language: "html".into() }),
1355    ///         Event::End(Container::Document),
1356    ///     ],
1357    /// );
1358    /// let html = concat!(
1359    ///     "<pre><code class=\"language-html\">&lt;tag&gt;x&lt;/tag&gt;\n",
1360    ///     "</code></pre>\n",
1361    /// );
1362    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1363    /// ```
1364    CodeBlock { language: CowStr<'s> },
1365    /// An inline divider element.
1366    ///
1367    /// # Examples
1368    ///
1369    /// Can be used to add attributes:
1370    ///
1371    /// ```
1372    /// # use jotdown::*;
1373    /// let src = concat!(
1374    ///     "word{#a}\n",
1375    ///     "[two words]{#b}\n",
1376    /// );
1377    /// let events: Vec<_> = Parser::new(src).collect();
1378    /// assert_eq!(
1379    ///     &events,
1380    ///     &[
1381    ///         Event::Start(Container::Document, Attributes::new()),
1382    ///         Event::Start(Container::Paragraph, Attributes::new()),
1383    ///         Event::Start(
1384    ///             Container::Span,
1385    ///             [(AttributeKind::Id, "a".into())].into_iter().collect(),
1386    ///         ),
1387    ///         Event::Str("word".into()),
1388    ///         Event::End(Container::Span),
1389    ///         Event::Softbreak,
1390    ///         Event::Start(
1391    ///             Container::Span,
1392    ///             [(AttributeKind::Id, "b".into())].into_iter().collect(),
1393    ///         ),
1394    ///         Event::Str("two words".into()),
1395    ///         Event::End(Container::Span),
1396    ///         Event::End(Container::Paragraph),
1397    ///         Event::End(Container::Document),
1398    ///     ],
1399    /// );
1400    /// let html = concat!(
1401    ///     "<p><span id=\"a\">word</span>\n",
1402    ///     "<span id=\"b\">two words</span></p>\n",
1403    /// );
1404    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1405    /// ```
1406    Span,
1407    /// An inline link, the first field is either a destination URL or an unresolved tag.
1408    ///
1409    /// # Examples
1410    ///
1411    /// URLs or email addresses can be enclosed with angled brackets to create a hyperlink:
1412    ///
1413    /// ```
1414    /// # use jotdown::*;
1415    /// let src = concat!(
1416    ///     "<https://example.com>\n",
1417    ///     "<me@example.com>\n",
1418    /// );
1419    /// let events: Vec<_> = Parser::new(src).collect();
1420    /// assert_eq!(
1421    ///     &events,
1422    ///     &[
1423    ///         Event::Start(Container::Document, Attributes::new()),
1424    ///         Event::Start(Container::Paragraph, Attributes::new()),
1425    ///         Event::Start(
1426    ///             Container::Link(
1427    ///                 "https://example.com".into(),
1428    ///                 LinkType::AutoLink,
1429    ///             ),
1430    ///             Attributes::new(),
1431    ///         ),
1432    ///         Event::Str("https://example.com".into()),
1433    ///         Event::End(Container::Link(
1434    ///             "https://example.com".into(),
1435    ///             LinkType::AutoLink,
1436    ///         )),
1437    ///         Event::Softbreak,
1438    ///         Event::Start(
1439    ///             Container::Link(
1440    ///                 "me@example.com".into(),
1441    ///                 LinkType::Email,
1442    ///             ),
1443    ///             Attributes::new(),
1444    ///         ),
1445    ///         Event::Str("me@example.com".into()),
1446    ///         Event::End(Container::Link(
1447    ///             "me@example.com".into(),
1448    ///             LinkType::Email,
1449    ///         )),
1450    ///         Event::End(Container::Paragraph),
1451    ///         Event::End(Container::Document),
1452    ///     ],
1453    /// );
1454    /// let html = concat!(
1455    ///     "<p><a href=\"https://example.com\">https://example.com</a>\n",
1456    ///     "<a href=\"mailto:me@example.com\">me@example.com</a></p>\n",
1457    /// );
1458    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1459    /// ```
1460    ///
1461    /// Anchor text and the URL can be specified inline:
1462    ///
1463    /// ```
1464    /// # use jotdown::*;
1465    /// let src = "[anchor](url)\n";
1466    /// let events: Vec<_> = Parser::new(src).collect();
1467    /// assert_eq!(
1468    ///     &events,
1469    ///     &[
1470    ///         Event::Start(Container::Document, Attributes::new()),
1471    ///         Event::Start(Container::Paragraph, Attributes::new()),
1472    ///         Event::Start(
1473    ///             Container::Link(
1474    ///                 "url".into(),
1475    ///                 LinkType::Span(SpanLinkType::Inline),
1476    ///             ),
1477    ///             Attributes::new(),
1478    ///         ),
1479    ///         Event::Str("anchor".into()),
1480    ///         Event::End(
1481    ///             Container::Link("url".into(),
1482    ///             LinkType::Span(SpanLinkType::Inline)),
1483    ///         ),
1484    ///         Event::End(Container::Paragraph),
1485    ///         Event::End(Container::Document),
1486    ///     ],
1487    /// );
1488    /// let html = "<p><a href=\"url\">anchor</a></p>\n";
1489    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1490    /// ```
1491    ///
1492    /// Alternatively, the URL can be retrieved from a link definition using hard brackets, if it
1493    /// exists:
1494    ///
1495    /// ```
1496    /// # use jotdown::*;
1497    /// let src = concat!(
1498    ///     "[a][label]\n",
1499    ///     "[b][non-existent]\n",
1500    ///     "\n",
1501    ///     "[label]: url\n",
1502    /// );
1503    /// let events: Vec<_> = Parser::new(src).collect();
1504    /// assert_eq!(
1505    ///     &events,
1506    ///     &[
1507    ///         Event::Start(Container::Document, Attributes::new()),
1508    ///         Event::Start(Container::Paragraph, Attributes::new()),
1509    ///         Event::Start(
1510    ///             Container::Link(
1511    ///                 "url".into(),
1512    ///                 LinkType::Span(SpanLinkType::Reference),
1513    ///             ),
1514    ///             Attributes::new(),
1515    ///         ),
1516    ///         Event::Str("a".into()),
1517    ///         Event::End(
1518    ///             Container::Link("url".into(),
1519    ///             LinkType::Span(SpanLinkType::Reference)),
1520    ///         ),
1521    ///         Event::Softbreak,
1522    ///         Event::Start(
1523    ///             Container::Link(
1524    ///                 "non-existent".into(),
1525    ///                 LinkType::Span(SpanLinkType::Unresolved),
1526    ///             ),
1527    ///             Attributes::new(),
1528    ///         ),
1529    ///         Event::Str("b".into()),
1530    ///         Event::End(
1531    ///             Container::Link("non-existent".into(),
1532    ///             LinkType::Span(SpanLinkType::Unresolved)),
1533    ///         ),
1534    ///         Event::End(Container::Paragraph),
1535    ///         Event::Blankline,
1536    ///         Event::Start(
1537    ///             Container::LinkDefinition { label: "label".into() },
1538    ///             Attributes::new(),
1539    ///         ),
1540    ///         Event::Str("url".into()),
1541    ///         Event::End(Container::LinkDefinition { label: "label".into() }),
1542    ///         Event::End(Container::Document),
1543    ///     ],
1544    /// );
1545    /// let html = concat!(
1546    ///     "<p><a href=\"url\">a</a>\n",
1547    ///     "<a>b</a></p>\n",
1548    /// );
1549    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1550    /// ```
1551    Link(CowStr<'s>, LinkType),
1552    /// An inline image, the first field is either a destination URL or an unresolved tag.
1553    ///
1554    /// # Examples
1555    ///
1556    /// Inner Str objects compose the alternative text:
1557    ///
1558    /// ```
1559    /// # use jotdown::*;
1560    /// let src = "![alt text](img.png)";
1561    /// let events: Vec<_> = Parser::new(src).collect();
1562    /// assert_eq!(
1563    ///     &events,
1564    ///     &[
1565    ///         Event::Start(Container::Document, Attributes::new()),
1566    ///         Event::Start(Container::Paragraph, Attributes::new()),
1567    ///         Event::Start(
1568    ///             Container::Image("img.png".into(), SpanLinkType::Inline),
1569    ///             Attributes::new(),
1570    ///         ),
1571    ///         Event::Str("alt text".into()),
1572    ///         Event::End(
1573    ///             Container::Image("img.png".into(), SpanLinkType::Inline),
1574    ///         ),
1575    ///         Event::End(Container::Paragraph),
1576    ///         Event::End(Container::Document),
1577    ///     ],
1578    /// );
1579    /// let html = "<p><img alt=\"alt text\" src=\"img.png\"></p>\n";
1580    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1581    /// ```
1582    Image(CowStr<'s>, SpanLinkType),
1583    /// An inline verbatim string.
1584    ///
1585    /// # Examples
1586    ///
1587    /// ```
1588    /// # use jotdown::*;
1589    /// let src = "inline `verbatim`";
1590    /// let events: Vec<_> = Parser::new(src).collect();
1591    /// assert_eq!(
1592    ///     &events,
1593    ///     &[
1594    ///         Event::Start(Container::Document, Attributes::new()),
1595    ///         Event::Start(Container::Paragraph, Attributes::new()),
1596    ///         Event::Str("inline ".into()),
1597    ///         Event::Start(Container::Verbatim, Attributes::new()),
1598    ///         Event::Str("verbatim".into()),
1599    ///         Event::End(Container::Verbatim),
1600    ///         Event::End(Container::Paragraph),
1601    ///         Event::End(Container::Document),
1602    ///     ],
1603    /// );
1604    /// let html = "<p>inline <code>verbatim</code></p>\n";
1605    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1606    /// ```
1607    Verbatim,
1608    /// An inline or display math element.
1609    ///
1610    /// # Examples
1611    ///
1612    /// ```
1613    /// # use jotdown::*;
1614    /// let src = concat!(
1615    ///     "inline $`a\\cdot{}b` or\n",
1616    ///     "display $$`\\frac{a}{b}`\n",
1617    /// );
1618    /// let events: Vec<_> = Parser::new(src).collect();
1619    /// assert_eq!(
1620    ///     &events,
1621    ///     &[
1622    ///         Event::Start(Container::Document, Attributes::new()),
1623    ///         Event::Start(Container::Paragraph, Attributes::new()),
1624    ///         Event::Str("inline ".into()),
1625    ///         Event::Start(
1626    ///             Container::Math { display: false },
1627    ///             Attributes::new(),
1628    ///         ),
1629    ///         Event::Str(r"a\cdot{}b".into()),
1630    ///         Event::End(Container::Math { display: false }),
1631    ///         Event::Str(" or".into()),
1632    ///         Event::Softbreak,
1633    ///         Event::Str("display ".into()),
1634    ///         Event::Start(
1635    ///             Container::Math { display: true },
1636    ///             Attributes::new(),
1637    ///         ),
1638    ///         Event::Str(r"\frac{a}{b}".into()),
1639    ///         Event::End(Container::Math { display: true }),
1640    ///         Event::End(Container::Paragraph),
1641    ///         Event::End(Container::Document),
1642    ///     ],
1643    /// );
1644    /// let html = concat!(
1645    ///     "<p>inline <span class=\"math inline\">\\(a\\cdot{}b\\)</span> or\n",
1646    ///     "display <span class=\"math display\">\\[\\frac{a}{b}\\]</span></p>\n",
1647    /// );
1648    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1649    /// ```
1650    Math { display: bool },
1651    /// Inline raw markup for a specific output format.
1652    ///
1653    /// # Examples
1654    ///
1655    /// ```
1656    /// # use jotdown::*;
1657    /// let src = "`<tag>a</tag>`{=html}";
1658    /// let events: Vec<_> = Parser::new(src).collect();
1659    /// assert_eq!(
1660    ///     &events,
1661    ///     &[
1662    ///         Event::Start(Container::Document, Attributes::new()),
1663    ///         Event::Start(Container::Paragraph, Attributes::new()),
1664    ///         Event::Start(
1665    ///             Container::RawInline { format: "html".into() }, Attributes::new(),
1666    ///         ),
1667    ///         Event::Str("<tag>a</tag>".into()),
1668    ///         Event::End(Container::RawInline { format: "html".into() }),
1669    ///         Event::End(Container::Paragraph),
1670    ///         Event::End(Container::Document),
1671    ///     ],
1672    /// );
1673    /// let html = "<p><tag>a</tag></p>\n";
1674    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1675    /// ```
1676    RawInline { format: CowStr<'s> },
1677    /// A subscripted element.
1678    ///
1679    /// # Examples
1680    ///
1681    /// ```
1682    /// # use jotdown::*;
1683    /// let src = "~SUB~";
1684    /// let events: Vec<_> = Parser::new(src).collect();
1685    /// assert_eq!(
1686    ///     &events,
1687    ///     &[
1688    ///         Event::Start(Container::Document, Attributes::new()),
1689    ///         Event::Start(Container::Paragraph, Attributes::new()),
1690    ///         Event::Start(Container::Subscript, Attributes::new()),
1691    ///         Event::Str("SUB".into()),
1692    ///         Event::End(Container::Subscript),
1693    ///         Event::End(Container::Paragraph),
1694    ///         Event::End(Container::Document),
1695    ///     ],
1696    /// );
1697    /// let html = "<p><sub>SUB</sub></p>\n";
1698    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1699    /// ```
1700    Subscript,
1701    /// A superscripted element.
1702    ///
1703    /// # Examples
1704    ///
1705    /// ```
1706    /// # use jotdown::*;
1707    /// let src = "^SUP^";
1708    /// let events: Vec<_> = Parser::new(src).collect();
1709    /// assert_eq!(
1710    ///     &events,
1711    ///     &[
1712    ///         Event::Start(Container::Document, Attributes::new()),
1713    ///         Event::Start(Container::Paragraph, Attributes::new()),
1714    ///         Event::Start(Container::Superscript, Attributes::new()),
1715    ///         Event::Str("SUP".into()),
1716    ///         Event::End(Container::Superscript),
1717    ///         Event::End(Container::Paragraph),
1718    ///         Event::End(Container::Document),
1719    ///     ],
1720    /// );
1721    /// let html = "<p><sup>SUP</sup></p>\n";
1722    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1723    /// ```
1724    Superscript,
1725    /// An inserted inline element.
1726    ///
1727    /// # Examples
1728    ///
1729    /// ```
1730    /// # use jotdown::*;
1731    /// let src = "{+INS+}";
1732    /// let events: Vec<_> = Parser::new(src).collect();
1733    /// assert_eq!(
1734    ///     &events,
1735    ///     &[
1736    ///         Event::Start(Container::Document, Attributes::new()),
1737    ///         Event::Start(Container::Paragraph, Attributes::new()),
1738    ///         Event::Start(Container::Insert, Attributes::new()),
1739    ///         Event::Str("INS".into()),
1740    ///         Event::End(Container::Insert),
1741    ///         Event::End(Container::Paragraph),
1742    ///         Event::End(Container::Document),
1743    ///     ],
1744    /// );
1745    /// let html = "<p><ins>INS</ins></p>\n";
1746    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1747    /// ```
1748    Insert,
1749    /// A deleted inline element.
1750    ///
1751    /// # Examples
1752    ///
1753    /// ```
1754    /// # use jotdown::*;
1755    /// let src = "{-DEL-}";
1756    /// let events: Vec<_> = Parser::new(src).collect();
1757    /// assert_eq!(
1758    ///     &events,
1759    ///     &[
1760    ///         Event::Start(Container::Document, Attributes::new()),
1761    ///         Event::Start(Container::Paragraph, Attributes::new()),
1762    ///         Event::Start(Container::Delete, Attributes::new()),
1763    ///         Event::Str("DEL".into()),
1764    ///         Event::End(Container::Delete),
1765    ///         Event::End(Container::Paragraph),
1766    ///         Event::End(Container::Document),
1767    ///     ],
1768    /// );
1769    /// let html = "<p><del>DEL</del></p>\n";
1770    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1771    /// ```
1772    Delete,
1773    /// An inline element emphasized with a bold typeface.
1774    ///
1775    /// # Examples
1776    ///
1777    /// ```
1778    /// # use jotdown::*;
1779    /// let src = "*STRONG*";
1780    /// let events: Vec<_> = Parser::new(src).collect();
1781    /// assert_eq!(
1782    ///     &events,
1783    ///     &[
1784    ///         Event::Start(Container::Document, Attributes::new()),
1785    ///         Event::Start(Container::Paragraph, Attributes::new()),
1786    ///         Event::Start(Container::Strong, Attributes::new()),
1787    ///         Event::Str("STRONG".into()),
1788    ///         Event::End(Container::Strong),
1789    ///         Event::End(Container::Paragraph),
1790    ///         Event::End(Container::Document),
1791    ///     ],
1792    /// );
1793    /// let html = "<p><strong>STRONG</strong></p>\n";
1794    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1795    /// ```
1796    Strong,
1797    /// An emphasized inline element.
1798    ///
1799    /// # Examples
1800    ///
1801    /// ```
1802    /// # use jotdown::*;
1803    /// let src = "_EM_";
1804    /// let events: Vec<_> = Parser::new(src).collect();
1805    /// assert_eq!(
1806    ///     &events,
1807    ///     &[
1808    ///         Event::Start(Container::Document, Attributes::new()),
1809    ///         Event::Start(Container::Paragraph, Attributes::new()),
1810    ///         Event::Start(Container::Emphasis, Attributes::new()),
1811    ///         Event::Str("EM".into()),
1812    ///         Event::End(Container::Emphasis),
1813    ///         Event::End(Container::Paragraph),
1814    ///         Event::End(Container::Document),
1815    ///     ],
1816    /// );
1817    /// let html = "<p><em>EM</em></p>\n";
1818    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1819    /// ```
1820    Emphasis,
1821    /// A highlighted inline element.
1822    ///
1823    /// # Examples
1824    ///
1825    /// ```
1826    /// # use jotdown::*;
1827    /// let src = "{=MARK=}";
1828    /// let events: Vec<_> = Parser::new(src).collect();
1829    /// assert_eq!(
1830    ///     &events,
1831    ///     &[
1832    ///         Event::Start(Container::Document, Attributes::new()),
1833    ///         Event::Start(Container::Paragraph, Attributes::new()),
1834    ///         Event::Start(Container::Mark, Attributes::new()),
1835    ///         Event::Str("MARK".into()),
1836    ///         Event::End(Container::Mark),
1837    ///         Event::End(Container::Paragraph),
1838    ///         Event::End(Container::Document),
1839    ///     ],
1840    /// );
1841    /// let html = "<p><mark>MARK</mark></p>\n";
1842    /// assert_eq!(&html::render_to_string(events.into_iter()), html);
1843    /// ```
1844    Mark,
1845}
1846
1847impl Container<'_> {
1848    /// Is a block element.
1849    #[must_use]
1850    pub fn is_block(&self) -> bool {
1851        match self {
1852            Self::Blockquote
1853            | Self::List { .. }
1854            | Self::ListItem
1855            | Self::TaskListItem { .. }
1856            | Self::DescriptionList
1857            | Self::DescriptionDetails
1858            | Self::Footnote { .. }
1859            | Self::Table
1860            | Self::TableRow { .. }
1861            | Self::Section { .. }
1862            | Self::Div { .. }
1863            | Self::Paragraph
1864            | Self::Heading { .. }
1865            | Self::TableCell { .. }
1866            | Self::Caption
1867            | Self::DescriptionTerm
1868            | Self::LinkDefinition { .. }
1869            | Self::RawBlock { .. }
1870            | Self::CodeBlock { .. } => true,
1871            Self::Document
1872            | Self::Span
1873            | Self::Link(..)
1874            | Self::Image(..)
1875            | Self::Verbatim
1876            | Self::Math { .. }
1877            | Self::RawInline { .. }
1878            | Self::Subscript
1879            | Self::Superscript
1880            | Self::Insert
1881            | Self::Delete
1882            | Self::Strong
1883            | Self::Emphasis
1884            | Self::Mark => false,
1885        }
1886    }
1887
1888    /// Is a block element that may contain children blocks.
1889    #[must_use]
1890    pub fn is_block_container(&self) -> bool {
1891        match self {
1892            Self::Blockquote
1893            | Self::List { .. }
1894            | Self::ListItem
1895            | Self::TaskListItem { .. }
1896            | Self::DescriptionList
1897            | Self::DescriptionDetails
1898            | Self::Footnote { .. }
1899            | Self::Table
1900            | Self::TableRow { .. }
1901            | Self::Section { .. }
1902            | Self::Div { .. } => true,
1903            Self::Document
1904            | Self::Paragraph
1905            | Self::Heading { .. }
1906            | Self::TableCell { .. }
1907            | Self::Caption
1908            | Self::DescriptionTerm
1909            | Self::LinkDefinition { .. }
1910            | Self::RawBlock { .. }
1911            | Self::CodeBlock { .. }
1912            | Self::Span
1913            | Self::Link(..)
1914            | Self::Image(..)
1915            | Self::Verbatim
1916            | Self::Math { .. }
1917            | Self::RawInline { .. }
1918            | Self::Subscript
1919            | Self::Superscript
1920            | Self::Insert
1921            | Self::Delete
1922            | Self::Strong
1923            | Self::Emphasis
1924            | Self::Mark => false,
1925        }
1926    }
1927}
1928
1929/// Alignment of a table column.
1930#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1931pub enum Alignment {
1932    Unspecified,
1933    Left,
1934    Center,
1935    Right,
1936}
1937
1938/// The type of an inline span link.
1939#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1940pub enum SpanLinkType {
1941    /// E.g. `[text](url)`
1942    Inline,
1943    /// In the form `[text][tag]` or `[tag][]`.
1944    Reference,
1945    /// Like reference, but the tag is unresolved.
1946    Unresolved,
1947}
1948
1949/// The type of an inline link.
1950#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1951pub enum LinkType {
1952    /// E.g. `[text](url)`.
1953    Span(SpanLinkType),
1954    /// In the form `<url>`.
1955    AutoLink,
1956    /// In the form `<address>`.
1957    Email,
1958}
1959
1960/// Character used to create an unordered list item.
1961#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1962pub enum ListBulletType {
1963    /// `-`
1964    Dash,
1965    /// `*`
1966    Star,
1967    /// `+`
1968    Plus,
1969}
1970
1971impl TryFrom<u8> for ListBulletType {
1972    type Error = ();
1973
1974    fn try_from(c: u8) -> Result<Self, Self::Error> {
1975        match c {
1976            b'-' => Ok(Self::Dash),
1977            b'*' => Ok(Self::Star),
1978            b'+' => Ok(Self::Plus),
1979            _ => Err(()),
1980        }
1981    }
1982}
1983
1984impl TryFrom<char> for ListBulletType {
1985    type Error = ();
1986
1987    fn try_from(c: char) -> Result<Self, Self::Error> {
1988        u8::try_from(u32::from(c))
1989            .map_err(|_| ())
1990            .and_then(Self::try_from)
1991    }
1992}
1993
1994impl From<ListBulletType> for u8 {
1995    fn from(t: ListBulletType) -> Self {
1996        match t {
1997            ListBulletType::Dash => b'-',
1998            ListBulletType::Star => b'*',
1999            ListBulletType::Plus => b'+',
2000        }
2001    }
2002}
2003
2004impl From<ListBulletType> for char {
2005    fn from(t: ListBulletType) -> Self {
2006        u8::from(t).into()
2007    }
2008}
2009
2010/// The type of a list.
2011#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2012pub enum ListKind {
2013    /// A bullet list.
2014    Unordered(ListBulletType),
2015    /// An enumerated list.
2016    Ordered {
2017        numbering: OrderedListNumbering,
2018        style: OrderedListStyle,
2019        start: u64,
2020    },
2021    /// A task list.
2022    Task(ListBulletType),
2023}
2024
2025/// Numbering type of an ordered list.
2026#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2027pub enum OrderedListNumbering {
2028    /// Decimal numbering, e.g. `1)`.
2029    Decimal,
2030    /// Lowercase alphabetic numbering, e.g. `a)`.
2031    AlphaLower,
2032    /// Uppercase alphabetic numbering, e.g. `A)`.
2033    AlphaUpper,
2034    /// Lowercase roman or alphabetic numbering, e.g. `iv)`.
2035    RomanLower,
2036    /// Uppercase roman or alphabetic numbering, e.g. `IV)`.
2037    RomanUpper,
2038}
2039
2040/// Style of an ordered list.
2041#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2042pub enum OrderedListStyle {
2043    /// Number is followed by a period, e.g. `1.`.
2044    Period,
2045    /// Number is followed by a closing parenthesis, e.g. `1)`.
2046    Paren,
2047    /// Number is enclosed by parentheses, e.g. `(1)`.
2048    ParenParen,
2049}
2050
2051impl OrderedListNumbering {
2052    fn parse_number(self, n: &str) -> u64 {
2053        match self {
2054            Self::Decimal => n.parse().unwrap(),
2055            Self::AlphaLower | Self::AlphaUpper => {
2056                let d0 = u64::from(if matches!(self, Self::AlphaLower) {
2057                    b'a'
2058                } else {
2059                    b'A'
2060                });
2061                let weights = (1..=n.len()).scan(1, |a, _| {
2062                    let prev = *a;
2063                    *a *= 26;
2064                    Some(prev)
2065                });
2066                n.as_bytes()
2067                    .iter()
2068                    .rev()
2069                    .copied()
2070                    .map(u64::from)
2071                    .zip(weights)
2072                    .map(|(d, w)| w * (d - d0 + 1))
2073                    .sum()
2074            }
2075            Self::RomanLower | Self::RomanUpper => {
2076                fn value(d: char) -> u64 {
2077                    match d {
2078                        'i' | 'I' => 1,
2079                        'v' | 'V' => 5,
2080                        'x' | 'X' => 10,
2081                        'l' | 'L' => 50,
2082                        'c' | 'C' => 100,
2083                        'd' | 'D' => 500,
2084                        'm' | 'M' => 1000,
2085                        _ => panic!(),
2086                    }
2087                }
2088                let mut prev = 0;
2089                let mut sum = 0;
2090                for d in n.chars().rev() {
2091                    let v = value(d);
2092                    if v < prev {
2093                        sum -= v;
2094                    } else {
2095                        sum += v;
2096                    }
2097                    prev = v;
2098                }
2099                sum
2100            }
2101        }
2102    }
2103}
2104
2105impl OrderedListStyle {
2106    fn number(self, marker: &str) -> &str {
2107        &marker[usize::from(matches!(self, Self::ParenParen))..marker.len() - 1]
2108    }
2109}
2110
2111#[cfg(not(feature = "deterministic"))]
2112type Map<K, V> = std::collections::HashMap<K, V>;
2113#[cfg(feature = "deterministic")]
2114type Map<K, V> = std::collections::BTreeMap<K, V>;
2115
2116#[cfg(not(feature = "deterministic"))]
2117type Set<T> = std::collections::HashSet<T>;
2118#[cfg(feature = "deterministic")]
2119type Set<T> = std::collections::BTreeSet<T>;
2120
2121/// A parser that generates [`Event`]s from a Djot document.
2122///
2123/// When created, it will perform an initial pass and build up a tree of the document's block
2124/// structure that will be kept for the duration of the parser's lifetime. Then, when the iterator
2125/// is advanced, the parser will start from the beginning of the document and parse inline elements
2126/// and emit [`Event`]s.
2127///
2128/// It is possible to clone the parser to e.g. avoid performing the block parsing multiple times.
2129#[derive(Clone)]
2130pub struct Parser<'s> {
2131    src: &'s str,
2132
2133    /// Block tree parsed at first.
2134    blocks: std::iter::Peekable<std::vec::IntoIter<block::Event<'s>>>,
2135
2136    /// Contents obtained by the prepass.
2137    pre_pass: PrePass<'s>,
2138
2139    /// Last parsed block attributes, and its span.
2140    block_attributes: Option<(Attributes<'s>, std::ops::Range<usize>)>,
2141
2142    /// Current table row is a head row.
2143    table_head_row: bool,
2144
2145    /// Currently within a verbatim code block.
2146    verbatim: bool,
2147
2148    /// Inline parser.
2149    inline_parser: inline::Parser<'s>,
2150}
2151
2152#[derive(Clone)]
2153struct Heading {
2154    /// Location of heading in src.
2155    location: u32,
2156    /// Automatically generated id from heading text.
2157    id_auto: String,
2158    /// Text of heading, formatting stripped.
2159    text: String,
2160    /// Overriding id from an explicit attribute on the heading.
2161    id_override: Option<String>,
2162}
2163
2164/// Because of potential future references, an initial pass is required to obtain all definitions.
2165#[derive(Clone)]
2166struct PrePass<'s> {
2167    /// Link definitions and their attributes.
2168    link_definitions: Map<&'s str, (CowStr<'s>, attr::Attributes<'s>)>,
2169    /// Cache of all heading ids.
2170    headings: Vec<Heading>,
2171    /// Indices to headings sorted lexicographically.
2172    headings_lex: Vec<usize>,
2173}
2174
2175impl<'s> PrePass<'s> {
2176    #[must_use]
2177    fn new(
2178        src: &'s str,
2179        mut blocks: std::slice::Iter<block::Event<'s>>,
2180        inline_parser: &mut inline::Parser<'s>,
2181    ) -> Self {
2182        use std::fmt::Write;
2183        let mut link_definitions = Map::new();
2184        let mut headings: Vec<Heading> = Vec::new();
2185        let mut used_ids: Set<String> = Set::new();
2186
2187        let mut attr_prev: Vec<std::ops::Range<usize>> = Vec::new();
2188        while let Some(e) = blocks.next() {
2189            match e.kind {
2190                block::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition {
2191                    label,
2192                })) => {
2193                    // All link definition tags have to be obtained initially, as references can
2194                    // appear before the definition.
2195                    let attrs = attr_prev
2196                        .iter()
2197                        .flat_map(|sp| {
2198                            Attributes::try_from(&src[sp.clone()]).expect("should be valid")
2199                        })
2200                        .collect::<Attributes>();
2201                    let url = if let Some(block::Event {
2202                        kind: block::EventKind::Inline,
2203                        span,
2204                    }) = blocks.next()
2205                    {
2206                        let start =
2207                            src[span.clone()].trim_matches(|c: char| c.is_ascii_whitespace());
2208                        if let Some(block::Event {
2209                            kind: block::EventKind::Inline,
2210                            span,
2211                        }) = blocks.next()
2212                        {
2213                            let mut url = start.to_string();
2214                            url.push_str(
2215                                src[span.clone()].trim_matches(|c: char| c.is_ascii_whitespace()),
2216                            );
2217                            while let Some(block::Event {
2218                                kind: block::EventKind::Inline,
2219                                span,
2220                            }) = blocks.next()
2221                            {
2222                                url.push_str(
2223                                    src[span.clone()]
2224                                        .trim_matches(|c: char| c.is_ascii_whitespace()),
2225                                );
2226                            }
2227                            url.into() // owned
2228                        } else {
2229                            start.into() // borrowed
2230                        }
2231                    } else {
2232                        "".into() // static
2233                    };
2234                    link_definitions.insert(label, (url, attrs));
2235                }
2236                block::EventKind::Enter(block::Node::Leaf(block::Leaf::Heading { .. })) => {
2237                    // All headings ids have to be obtained initially, as references can appear
2238                    // before the heading. Additionally, determining the id requires inline parsing
2239                    // as formatting must be removed.
2240                    //
2241                    // We choose to parse all headers twice instead of caching them.
2242                    let attrs = attr_prev
2243                        .iter()
2244                        .flat_map(|sp| {
2245                            Attributes::try_from(&src[sp.clone()]).expect("should be valid")
2246                        })
2247                        .collect::<Attributes>();
2248                    let id_override = attrs.get_value("id").map(|s| s.to_string());
2249
2250                    let mut id_auto = String::new();
2251                    let mut text = String::new();
2252                    let mut last_whitespace = true;
2253                    inline_parser.reset();
2254                    let mut last_end = 0;
2255                    loop {
2256                        let span_inline = blocks.next().and_then(|e| {
2257                            if matches!(e.kind, block::EventKind::Inline) {
2258                                last_end = e.span.end;
2259                                Some(e.span.clone())
2260                            } else {
2261                                None
2262                            }
2263                        });
2264                        inline_parser.feed_line(
2265                            span_inline.clone().unwrap_or(last_end..last_end),
2266                            span_inline.is_none(),
2267                        );
2268                        inline_parser.for_each(|ev| match ev.kind {
2269                            inline::EventKind::Str => {
2270                                text.push_str(&src[ev.span.clone()]);
2271                                let mut chars = src[ev.span].chars().peekable();
2272                                while let Some(c) = chars.next() {
2273                                    if c.is_ascii_whitespace() {
2274                                        while chars.peek().is_some_and(char::is_ascii_whitespace) {
2275                                            chars.next();
2276                                        }
2277                                        if !last_whitespace {
2278                                            last_whitespace = true;
2279                                            id_auto.push('-');
2280                                        }
2281                                    } else if !c.is_ascii_punctuation() || matches!(c, '-' | '_') {
2282                                        id_auto.push(c);
2283                                        last_whitespace = false;
2284                                    }
2285                                }
2286                            }
2287                            inline::EventKind::Atom(inline::Atom::Softbreak) => {
2288                                text.push(' ');
2289                                id_auto.push('-');
2290                            }
2291                            _ => {}
2292                        });
2293                        if span_inline.is_none() {
2294                            break;
2295                        }
2296                    }
2297                    id_auto.drain(id_auto.trim_end_matches('-').len()..);
2298
2299                    // ensure id unique
2300                    if used_ids.contains::<str>(&id_auto) || id_auto.is_empty() {
2301                        if id_auto.is_empty() {
2302                            id_auto.push('s');
2303                        }
2304                        let mut num = 1;
2305                        id_auto.push('-');
2306                        let i_num = id_auto.len();
2307                        write!(id_auto, "{num}").unwrap();
2308                        while used_ids.contains::<str>(&id_auto) {
2309                            num += 1;
2310                            id_auto.drain(i_num..);
2311                            write!(id_auto, "{num}").unwrap();
2312                        }
2313                    }
2314
2315                    used_ids.insert(id_auto.clone());
2316                    headings.push(Heading {
2317                        location: e.span.start as u32,
2318                        id_auto,
2319                        text,
2320                        id_override,
2321                    });
2322                }
2323                block::EventKind::Atom(block::Atom::Attributes) => {
2324                    attr_prev.push(e.span.clone());
2325                }
2326                block::EventKind::Enter(..)
2327                | block::EventKind::Exit(block::Node::Container(block::Container::Section {
2328                    ..
2329                })) => {}
2330                _ => {
2331                    attr_prev = Vec::new();
2332                }
2333            }
2334        }
2335
2336        let mut headings_lex = (0..headings.len()).collect::<Vec<_>>();
2337        headings_lex.sort_by_key(|i| &headings[*i].text);
2338
2339        Self {
2340            link_definitions,
2341            headings,
2342            headings_lex,
2343        }
2344    }
2345
2346    fn heading_id(&self, i: usize) -> &str {
2347        let h = &self.headings[i];
2348        h.id_override.as_ref().unwrap_or(&h.id_auto)
2349    }
2350
2351    fn heading_id_by_location(&self, location: u32) -> Option<&str> {
2352        self.headings
2353            .binary_search_by_key(&location, |h| h.location)
2354            .ok()
2355            .map(|i| self.heading_id(i))
2356    }
2357
2358    fn heading_id_by_tag(&self, tag: &str) -> Option<&str> {
2359        self.headings_lex
2360            .binary_search_by_key(&tag, |i| &self.headings[*i].text)
2361            .ok()
2362            .map(|i| self.heading_id(self.headings_lex[i]))
2363    }
2364}
2365
2366impl<'s> Parser<'s> {
2367    #[must_use]
2368    pub fn new(src: &'s str) -> Self {
2369        let blocks = block::parse(src);
2370        let mut inline_parser = inline::Parser::new(src);
2371        let pre_pass = PrePass::new(src, blocks.iter(), &mut inline_parser);
2372
2373        Self {
2374            src,
2375            blocks: blocks.into_iter().peekable(),
2376            pre_pass,
2377            block_attributes: None,
2378            table_head_row: false,
2379            verbatim: false,
2380            inline_parser,
2381        }
2382    }
2383
2384    /// Turn the [`Parser`] into an iterator of tuples, each with an [`Event`] and a start/end byte
2385    /// offset for its corresponding input (as a [`std::ops::Range<usize>`]).
2386    ///
2387    /// Generally, the range of each event does not overlap with any other event and the ranges are
2388    /// in same order as the events are emitted, i.e. the start offset of an event must be greater
2389    /// or equal to the (exclusive) end offset of all events that were emitted before that event.
2390    /// However, there is an exception to this rule:
2391    ///
2392    /// - Caption events are emitted before the table rows while the input for the caption content
2393    ///   is located after the table rows, causing the ranges to be out of order.
2394    ///
2395    /// Characters between events, that are not part of any event range, are typically whitespace
2396    /// but may also consist of unattached attributes or `>` characters from blockquotes.
2397    ///
2398    /// # Examples
2399    ///
2400    /// Start and end events of containers correspond only to the start and end markers for that
2401    /// container, not its inner content:
2402    ///
2403    /// ```
2404    /// # use jotdown::*;
2405    /// # use jotdown::Event::*;
2406    /// # use jotdown::Container::*;
2407    /// let input = "> _hello_ [text](url)\n";
2408    /// assert!(matches!(
2409    ///     Parser::new(input)
2410    ///         .into_offset_iter()
2411    ///         .map(|(e, r)| (&input[r], e))
2412    ///         .collect::<Vec<_>>()
2413    ///         .as_slice(),
2414    ///     &[
2415    ///         ("", Start(Document, ..)),
2416    ///         (">", Start(Blockquote, ..)),
2417    ///         ("", Start(Paragraph, ..)),
2418    ///         ("_", Start(Emphasis, ..)),
2419    ///         ("hello", Str(..)),
2420    ///         ("_", End(Emphasis)),
2421    ///         (" ", Str(..)),
2422    ///         ("[", Start(Link { .. }, ..)),
2423    ///         ("text", Str(..)),
2424    ///         ("](url)", End(Link { .. })),
2425    ///         ("", End(Paragraph)),
2426    ///         ("", End(Blockquote)),
2427    ///         ("", End(Document)),
2428    ///     ],
2429    /// ));
2430    /// ```
2431    ///
2432    /// _Block_ attributes that belong to a container are included in the  _start_ event.  _Inline_
2433    /// attributes that belong to a container are included in the _end_ event:
2434    ///
2435    /// ```
2436    /// # use jotdown::*;
2437    /// # use jotdown::Event::*;
2438    /// # use jotdown::Container::*;
2439    /// let input = "
2440    /// {.quote}
2441    /// > [Hello]{lang=en} world!";
2442    /// assert!(matches!(
2443    ///     Parser::new(input)
2444    ///         .into_offset_iter()
2445    ///         .map(|(e, r)| (&input[r], e))
2446    ///         .collect::<Vec<_>>()
2447    ///         .as_slice(),
2448    ///     &[
2449    ///         ("", Start(Document, ..)),
2450    ///         ("\n", Blankline),
2451    ///         ("{.quote}\n>", Start(Blockquote, ..)),
2452    ///         ("", Start(Paragraph, ..)),
2453    ///         ("[", Start(Span, ..)),
2454    ///         ("Hello", Str(..)),
2455    ///         ("]{lang=en}", End(Span)),
2456    ///         (" world!", Str(..)),
2457    ///         ("", End(Paragraph)),
2458    ///         ("", End(Blockquote)),
2459    ///         ("", End(Document)),
2460    ///     ],
2461    /// ));
2462    /// ```
2463    ///
2464    /// Inline events that span multiple lines may contain characters from outer block containers
2465    /// (e.g. `>` characters from blockquotes or whitespace from list items):
2466    ///
2467    /// ```
2468    /// # use jotdown::*;
2469    /// # use jotdown::Event::*;
2470    /// # use jotdown::Container::*;
2471    /// let input = "
2472    /// > [txt](multi
2473    /// > line)";
2474    /// assert!(matches!(
2475    ///     Parser::new(input)
2476    ///         .into_offset_iter()
2477    ///         .map(|(e, r)| (&input[r], e))
2478    ///         .collect::<Vec<_>>()
2479    ///         .as_slice(),
2480    ///     &[
2481    ///         ("", Start(Document, ..)),
2482    ///         ("\n", Blankline),
2483    ///         (">", Start(Blockquote, ..)),
2484    ///         ("", Start(Paragraph, ..)),
2485    ///         ("[", Start(Link { .. }, ..)),
2486    ///         ("txt", Str(..)),
2487    ///         ("](multi\n> line)", End(Link { .. })),
2488    ///         ("", End(Paragraph)),
2489    ///         ("", End(Blockquote)),
2490    ///         ("", End(Document)),
2491    ///     ],
2492    /// ));
2493    /// ```
2494    #[must_use]
2495    pub fn into_offset_iter(self) -> OffsetIter<'s> {
2496        OffsetIter { parser: self }
2497    }
2498
2499    fn inline(&mut self) -> Option<(Event<'s>, std::ops::Range<usize>)> {
2500        let next = self.inline_parser.next()?;
2501
2502        let (inline, mut attributes) = match next {
2503            inline::Event {
2504                kind: inline::EventKind::Attributes { attrs, .. },
2505                ..
2506            } => (
2507                self.inline_parser.next(),
2508                self.inline_parser.store_attributes[attrs as usize].clone(),
2509            ),
2510            inline => (Some(inline), Attributes::new()),
2511        };
2512
2513        let event = inline.map(|inline| {
2514            let enter = matches!(inline.kind, inline::EventKind::Enter(_));
2515            let event = match inline.kind {
2516                inline::EventKind::Enter(c) | inline::EventKind::Exit(c) => {
2517                    let t = match c {
2518                        inline::Container::Span => Container::Span,
2519                        inline::Container::Verbatim => Container::Verbatim,
2520                        inline::Container::InlineMath => Container::Math { display: false },
2521                        inline::Container::DisplayMath => Container::Math { display: true },
2522                        inline::Container::RawFormat { format } => Container::RawInline {
2523                            format: format.into(),
2524                        },
2525                        inline::Container::Subscript => Container::Subscript,
2526                        inline::Container::Superscript => Container::Superscript,
2527                        inline::Container::Insert => Container::Insert,
2528                        inline::Container::Delete => Container::Delete,
2529                        inline::Container::Emphasis => Container::Emphasis,
2530                        inline::Container::Strong => Container::Strong,
2531                        inline::Container::Mark => Container::Mark,
2532                        inline::Container::InlineLink(url) => Container::Link(
2533                            self.inline_parser.store_cowstrs[url as usize].clone(),
2534                            LinkType::Span(SpanLinkType::Inline),
2535                        ),
2536                        inline::Container::InlineImage(url) => Container::Image(
2537                            self.inline_parser.store_cowstrs[url as usize].clone(),
2538                            SpanLinkType::Inline,
2539                        ),
2540                        inline::Container::ReferenceLink(tag)
2541                        | inline::Container::ReferenceImage(tag) => {
2542                            let tag = &self.inline_parser.store_cowstrs[tag as usize];
2543                            let link_def =
2544                                self.pre_pass.link_definitions.get(tag.as_ref()).cloned();
2545
2546                            let (url_or_tag, ty) = if let Some((url, mut attrs_def)) = link_def {
2547                                if enter {
2548                                    attrs_def.append(&mut attributes);
2549                                    attributes = attrs_def;
2550                                }
2551                                (url, SpanLinkType::Reference)
2552                            } else {
2553                                self.pre_pass.heading_id_by_tag(tag.as_ref()).map_or_else(
2554                                    || (tag.clone(), SpanLinkType::Unresolved),
2555                                    |id| (format!("#{id}").into(), SpanLinkType::Reference),
2556                                )
2557                            };
2558
2559                            if matches!(c, inline::Container::ReferenceLink(..)) {
2560                                Container::Link(url_or_tag, LinkType::Span(ty))
2561                            } else {
2562                                Container::Image(url_or_tag, ty)
2563                            }
2564                        }
2565                        inline::Container::Autolink(url) => {
2566                            let ty = if url.contains('@') {
2567                                LinkType::Email
2568                            } else {
2569                                LinkType::AutoLink
2570                            };
2571                            Container::Link(url.into(), ty)
2572                        }
2573                    };
2574                    if enter {
2575                        Event::Start(t, attributes.take())
2576                    } else {
2577                        Event::End(t)
2578                    }
2579                }
2580                inline::EventKind::Atom(a) => match a {
2581                    inline::Atom::FootnoteReference { label } => {
2582                        Event::FootnoteReference(label.into())
2583                    }
2584                    inline::Atom::Symbol(sym) => Event::Symbol(sym.into()),
2585                    inline::Atom::Quote { ty, left } => match (ty, left) {
2586                        (inline::QuoteType::Single, true) => Event::LeftSingleQuote,
2587                        (inline::QuoteType::Single, false) => Event::RightSingleQuote,
2588                        (inline::QuoteType::Double, true) => Event::LeftDoubleQuote,
2589                        (inline::QuoteType::Double, false) => Event::RightDoubleQuote,
2590                    },
2591                    inline::Atom::Ellipsis => Event::Ellipsis,
2592                    inline::Atom::EnDash => Event::EnDash,
2593                    inline::Atom::EmDash => Event::EmDash,
2594                    inline::Atom::Nbsp => Event::NonBreakingSpace,
2595                    inline::Atom::Softbreak => Event::Softbreak,
2596                    inline::Atom::Hardbreak => Event::Hardbreak,
2597                    inline::Atom::Escape => Event::Escape,
2598                },
2599                inline::EventKind::Empty => {
2600                    debug_assert!(!attributes.is_empty());
2601                    Event::Attributes(attributes.take())
2602                }
2603                inline::EventKind::Str => Event::Str(self.src[inline.span.clone()].into()),
2604                inline::EventKind::Attributes { .. } | inline::EventKind::Placeholder => {
2605                    panic!("{inline:?}")
2606                }
2607            };
2608            (event, inline.span)
2609        });
2610
2611        debug_assert!(
2612            attributes.is_empty(),
2613            "unhandled attributes: {attributes:?}",
2614        );
2615
2616        event
2617    }
2618
2619    fn block(&mut self) -> Option<(Event<'s>, std::ops::Range<usize>)> {
2620        while let Some(ev) = self.blocks.peek() {
2621            let mut ev_span = ev.span.clone();
2622            let mut pop = true;
2623            let event = match ev.kind {
2624                block::EventKind::Atom(a) => match a {
2625                    block::Atom::Blankline => {
2626                        debug_assert_eq!(self.block_attributes, None);
2627                        Event::Blankline
2628                    }
2629                    block::Atom::ThematicBreak => {
2630                        let attrs = if let Some((attrs, span)) = self.block_attributes.take() {
2631                            ev_span.start = span.start;
2632                            attrs
2633                        } else {
2634                            Attributes::new()
2635                        };
2636                        Event::ThematicBreak(attrs)
2637                    }
2638                    block::Atom::Attributes => {
2639                        let (mut attrs, mut span) = self
2640                            .block_attributes
2641                            .take()
2642                            .unwrap_or_else(|| (Attributes::new(), ev_span.clone()));
2643                        attrs
2644                            .parse(&self.src[ev_span.clone()])
2645                            .expect("should be valid");
2646                        span.end = ev_span.end;
2647                        self.blocks.next().unwrap();
2648                        if matches!(
2649                            self.blocks.peek().map(|e| &e.kind),
2650                            Some(block::EventKind::Atom(block::Atom::Blankline))
2651                        ) {
2652                            return Some((Event::Attributes(attrs), span));
2653                        }
2654                        self.block_attributes = Some((attrs, span));
2655                        continue;
2656                    }
2657                },
2658                block::EventKind::Enter(c) | block::EventKind::Exit(c) => {
2659                    let enter = matches!(ev.kind, block::EventKind::Enter(..));
2660                    let cont = match c {
2661                        block::Node::Leaf(l) => {
2662                            self.inline_parser.reset();
2663                            match l {
2664                                block::Leaf::Paragraph => Container::Paragraph,
2665                                block::Leaf::Heading {
2666                                    level,
2667                                    has_section,
2668                                    pos,
2669                                } => Container::Heading {
2670                                    level,
2671                                    has_section,
2672                                    id: self
2673                                        .pre_pass
2674                                        .heading_id_by_location(pos)
2675                                        .unwrap_or_default()
2676                                        .to_string()
2677                                        .into(),
2678                                },
2679                                block::Leaf::DescriptionTerm => Container::DescriptionTerm,
2680                                block::Leaf::CodeBlock { language } => {
2681                                    self.verbatim = enter;
2682                                    if let Some(format) = language.strip_prefix('=') {
2683                                        Container::RawBlock {
2684                                            format: format.into(),
2685                                        }
2686                                    } else {
2687                                        Container::CodeBlock {
2688                                            language: language.into(),
2689                                        }
2690                                    }
2691                                }
2692                                block::Leaf::TableCell(alignment) => Container::TableCell {
2693                                    alignment,
2694                                    head: self.table_head_row,
2695                                },
2696                                block::Leaf::Caption => Container::Caption,
2697                                block::Leaf::LinkDefinition { label } => {
2698                                    self.verbatim = enter;
2699                                    Container::LinkDefinition {
2700                                        label: label.into(),
2701                                    }
2702                                }
2703                            }
2704                        }
2705                        block::Node::Container(c) => match c {
2706                            block::Container::Document => Container::Document,
2707                            block::Container::Blockquote => Container::Blockquote,
2708                            block::Container::Div { class } => Container::Div {
2709                                class: class.into(),
2710                            },
2711                            block::Container::Footnote { label } => Container::Footnote {
2712                                label: label.into(),
2713                            },
2714                            block::Container::List { ty, tight } => {
2715                                if matches!(ty, block::ListType::Description) {
2716                                    Container::DescriptionList
2717                                } else {
2718                                    let kind = match ty {
2719                                        block::ListType::Unordered(c) => ListKind::Unordered(
2720                                            c.try_into().expect("should be bullet character"),
2721                                        ),
2722                                        block::ListType::Task(c) => ListKind::Task(
2723                                            c.try_into().expect("should be bullet character"),
2724                                        ),
2725                                        block::ListType::Ordered(
2726                                            block::ListNumber { numbering, value },
2727                                            style,
2728                                        ) => ListKind::Ordered {
2729                                            numbering,
2730                                            style,
2731                                            start: value,
2732                                        },
2733                                        block::ListType::Description => unreachable!(),
2734                                    };
2735                                    Container::List { kind, tight }
2736                                }
2737                            }
2738                            block::Container::ListItem(kind) => match kind {
2739                                block::ListItemKind::Task { checked } => {
2740                                    Container::TaskListItem { checked }
2741                                }
2742                                block::ListItemKind::Description => Container::DescriptionDetails,
2743                                block::ListItemKind::List => Container::ListItem,
2744                            },
2745                            block::Container::Table => Container::Table,
2746                            block::Container::TableRow { head } => {
2747                                if enter {
2748                                    self.table_head_row = head;
2749                                }
2750                                Container::TableRow { head }
2751                            }
2752                            block::Container::Section { pos } => Container::Section {
2753                                id: self
2754                                    .pre_pass
2755                                    .heading_id_by_location(pos)
2756                                    .unwrap_or_default()
2757                                    .to_string()
2758                                    .into(),
2759                            },
2760                        },
2761                    };
2762                    if enter {
2763                        let attrs = if let Some((attrs, span)) = self.block_attributes.take() {
2764                            ev_span.start = span.start;
2765                            attrs
2766                        } else {
2767                            Attributes::new()
2768                        };
2769                        Event::Start(cont, attrs)
2770                    } else if let Some((attrs, sp)) = self.block_attributes.take() {
2771                        pop = false;
2772                        ev_span = sp;
2773                        Event::Attributes(attrs)
2774                    } else {
2775                        Event::End(cont)
2776                    }
2777                }
2778                block::EventKind::Inline => {
2779                    if self.verbatim {
2780                        if ev_span.is_empty() {
2781                            self.blocks.next().unwrap();
2782                            continue;
2783                        }
2784                        Event::Str(self.src[ev_span.clone()].into())
2785                    } else {
2786                        self.blocks.next().unwrap();
2787                        self.inline_parser.feed_line(
2788                            ev_span.clone(),
2789                            !matches!(
2790                                self.blocks.peek().map(|e| &e.kind),
2791                                Some(block::EventKind::Inline),
2792                            ),
2793                        );
2794                        return self.next_span();
2795                    }
2796                }
2797                block::EventKind::Stale => {
2798                    self.blocks.next().unwrap();
2799                    continue;
2800                }
2801            };
2802            if pop {
2803                self.blocks.next().unwrap();
2804            }
2805            return Some((event, ev_span));
2806        }
2807        None
2808    }
2809
2810    fn next_span(&mut self) -> Option<(Event<'s>, std::ops::Range<usize>)> {
2811        self.inline().or_else(|| self.block()).or_else(|| {
2812            self.block_attributes
2813                .take()
2814                .map(|(attrs, span)| (Event::Attributes(attrs), span))
2815        })
2816    }
2817}
2818
2819impl<'s> Iterator for Parser<'s> {
2820    type Item = Event<'s>;
2821
2822    fn next(&mut self) -> Option<Self::Item> {
2823        self.next_span().map(|(e, _)| e)
2824    }
2825}
2826
2827/// An iterator that is identical to a [`Parser`], except that it also emits the location of each
2828/// event within the input.
2829///
2830/// See the documentation of [`Parser::into_offset_iter`] for more information.
2831pub struct OffsetIter<'s> {
2832    parser: Parser<'s>,
2833}
2834
2835impl<'s> Iterator for OffsetIter<'s> {
2836    type Item = (Event<'s>, std::ops::Range<usize>);
2837
2838    fn next(&mut self) -> Option<Self::Item> {
2839        self.parser.next_span()
2840    }
2841}
2842
2843#[cfg(test)]
2844mod test {
2845    use super::OrderedListNumbering::*;
2846
2847    #[test]
2848    fn numbering_alpha() {
2849        assert_eq!(AlphaLower.parse_number("a"), 1);
2850        assert_eq!(AlphaUpper.parse_number("B"), 2);
2851        assert_eq!(AlphaUpper.parse_number("Z"), 26);
2852        assert_eq!(AlphaLower.parse_number("aa"), 27);
2853    }
2854}