r3bl_tui 0.7.0

TUI library to build modern apps inspired by React, Elm, with Flexbox, CSS, editor component, emoji support, and more
Documentation
/*
 *   Copyright (c) 2023-2025 R3BL LLC
 *   All rights reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

//! The main entry point (function) for this Markdown parsing module is
//! [parse_markdown()].
//! - It takes a string slice.
//! - And returns a vector of [MdBlock]s.
//!
//! This module contains a fully functional Markdown parser. This parser supports standard
//! Markdown syntax as well as some extensions that are added to make it work w/
//! [R3BL](https://r3bl.com) products.
//!
//! Here are some entry points into the codebase.
//!
//! 1. The main function [parse_markdown()] that does the parsing of a string slice into a
//!    [MdDocument]. The tests are provided alongside the code itself. And you can follow
//!    along to see how other smaller parsers are used to build up this big one that
//!    parses the whole of the Markdown document.
//! 2. The [mod@md_parser_types] contain all the types that are used to represent the
//!    Markdown document model, such as [MdDocument], [MdBlock], [MdLineFragment] and all
//!    the other intermediate types & enums required for parsing.
//! 3. All the parsers related to parsing metadata specific for [R3BL](https://r3bl.com)
//!    applications, which are not standard Markdown can be found in
//!    [mod@parse_metadata_kv] and [mod@parse_metadata_kcsv].
//! 4. All the parsers that are related to parsing the main "blocks" of Markdown, such as
//!    order lists, unordered lists, code blocks, text blocks, heading blocks, can be
//!    found in [mod@block].
//! 5. All the parsers that are related to parsing a single line of Markdown text, such as
//!    links, bold, italic, etc. can be found [mod@fragment].
//!
//! ## Video and blog post on this
//!
//! You can read all about this parser in [this blog post on
//! developerlife.com](https://developerlife.com/2024/06/28/md-parser-rust-from-r3bl-tui/).
//! You can watch a [video](https://youtu.be/SbwvSHZRb1E) about this parser on the YouTube
//! developerlife.com channel.
//!
//! To learn about nom fundamentals, here are some resources:
//! - Tutorial on nom parsing on [developerlife.com](https://developerlife.com/2023/02/20/guide-to-nom-parsing/).
//! - Video on nom parsing on [YouTube developerlife.com channel](https://youtu.be/v3tMwr_ysPg).
//!
//! ## Architecture and parsing order
//!
//! This diagram showcases the order in which the parsers are called and how they are
//! composed together to parse a Markdown document.
//!
//! <!--
//! diagram:
//! https://asciiflow.com/#/share/eJzdlL9qwzAQxl%2Fl0JRChhLo0Gz9M3Rop2YUCNUWsYgsGfkcxxhD6dyhQwh9ltKnyZNUtus0hAYrJaXQQyAZf%2F6d7rN0JdE8FmSsM6WGRPFCWDImJSULSsbnZ6MhJYVbjZoVigW6B0oSK42VWMB6%2BbxePv7T8UKpBojkNAJwlT5Bwm0qWMztLDS5HpxACTsR8wTQAEYCAmOtCHBX0aIacgvdTDHXxengG3331U8LWb0B3IWXygQzmHMrucZ9e4DPGlGiEmzOVSZcmb0xqeV99W3YfJoyJVP0ITu2k%2Fd617F5hpGx3viLVu7HDjkeYAlcO7n3vh%2Fqn8MiwUOpp8wkyIRR%2B9PctMJD2Kk7tujjy30tvHU6f3ZgQj9PrpywPYfe7O62sbr5sFxixIxtZpMh0yJ3Nek6%2B8S9%2F8q0h%2B114vpii71679jVMcgde6u%2FLv%2B6C%2F7eeG1cVCY%2FjnVdUFKR6gNnN4sV)
//! -->
//!
//! ```text
//! priority ┌────────────────────────────────────────────────────────────────────────┐
//!   high   │ parse_markdown() {                map to the correct                   │
//!     │    │   many0(                         ───────────────────►  MdBlock variant │
//!     │    │     parse_title_value()                                  Title         │
//!     │    │     parse_tags_list()                                    Tags          │
//!     │    │     parse_authors_list()                                 Authors       │
//!     │    │     parse_date_value()                                   Date          │
//!     │    │     parse_block_heading_opt_eol()                        Heading       │
//!     │    │     parse_block_smart_list()                             SmartList     │
//!     │    │     parse_block_code()                                   CodeBlock     │
//!     │    │     parse_block_markdown_text_with_or_without_new_line() Text          │
//!     │    │   )                                                                    │
//!     ▼    │ }                                                                      │
//! priority └────────────────────────────────────────────────────────────────────────┘
//!   low
//! ```
//! The parsing strategy in most cases is to parse the most specific thing first and then
//! parse the more general thing later. We often use the existence of `\n` (or `eol`) to
//! decide how far forwards we need to go into the input. And sometimes `\n` doesn't exist
//! and we simply use the entire input (or end of input or `eoi`). You might see functions
//! that have these suffixes in their names. Another term you might see is
//! `with_or_without_new_line` which makes the parsing strategy explicit in the name.
//!
//! The nature of `nom` parsers is to simply error out when they don't match. And leave
//! the `input` untouched, so that another parser have a go at it again. The nature of
//! these parsing functions is kind of recursive in nature. So it's important identify
//! edge and request_shutdown cases up front before diving into the parsing logic. You
//! will see this used in parsers which look for something more specific, if its not
//! found, they error out, and allow less specific parsers to have a go at it, and so on.
//!
//! ## The priority of parsers
//!
//! As we drill down into the implementation further, we see that the parsers are
//! prioritized in the order of their specificity. The most specific parsers are called
//! first and the least specific parsers are called last. This is done to ensure that the
//! most specific parsers get a chance to parse the input first. And if they fail, then
//! the less specific parsers get a chance to parse the input.
//!
//! <!--
//! diagram:
//! https://asciiflow.com/#/share/eJytlFFuwjAMhq8S5QkkHtD2MjhLJCsNBqK6CUpTUYaQpp2h4iB7RDtNT7I0sK1ABYNhVapdJ1%2F%2F2G7X3MgM%2BdgURANOcoWOj%2Fla8FLw8ejleSD4KnhPo2HwPJY%2BBIIvpMsRErIqhUy6dGKXBposLLWfg3XxbgsPBpdA2mCvz9bs3IQwjGXSrIa9juxtFlmM7bVp07wVpk7OMjQ%2Bh8J4TYCWGnVodRB0nRWsWVZX7%2F9VtvmNHkBrRXVV1dVbvd0xSf7OIh4TI3X7cSjkdwUh99KFOsYGF2aCLlfWIaBzYE27zx20cOILtMbv4LS05QtUWpJ%2BxclVWiJV6nUYzC5ipMXNLmdN3X6u7e4Kl3DqQWdy9pAzR1rY3CnzZpqao0oTW4ax9zZkXHu6u7r7%2BSfaMTaxlnr9SFPSq3kYODop4Sl1QVIffgzGnvf2ROO%2BL4cnFz%2FPiyb4hm%2B%2BAFpUbMk%3D)
//! -->
//!
//! ```text
//! parse_block_markdown_text_with_or_without_new_line() {
//!     many0(
//!       parse_inline_fragments_until_eol_or_eoi()
//!         )   │
//!   }         │                                                                 ──map to the correct──►
//!             └─► alt(                                                          MdLineFragment variant
//!                  ▲ parse_fragment_starts_with_underscore_err_on_new_line()      Italic
//!                  │ parse_fragment_starts_with_star_err_on_new_line()            Bold
//!     specialized  │ parse_fragment_starts_with_backtick_err_on_new_line()        InlineCode
//!     parsers ────►│ parse_fragment_starts_with_left_image_err_on_new_line()      Image
//!                  │ parse_fragment_starts_with_left_link_err_on_new_line()       Link
//!                  │ parse_fragment_starts_with_checkbox_into_str()               Plain
//!                  ▼ parse_fragment_starts_with_checkbox_checkbox_into_bool()     Checkbox
//!     catch all────► parse_fragment_plain_text_no_new_line()                      Plain
//!     parser       )
//! ```
//!
//! The last one on the list in the diagram above is
//! [parse_block_markdown_text_with_or_without_new_line()]. Let's zoom into this function
//! and see how it is composed.
//!
//! ## The "catch all" parser, which is the most complicated, and the lowest priority
//!
//! The most complicated parser is the "catch all" parser or the "plain text" parser. This
//! parser is the last one in the chain and it simply consumes the rest of the input and
//! turns it into a `MdBlock::Text`. This parser is the most complicated because it has to
//! deal with all the edge cases and request_shutdown cases that other parsers have not
//! dealt with. Such as special characters like `` ` ``, `*`, `_`, etc. They are all
//! listed here:
//!
//! - If the input does not start with a special char in this [get_sp_char_set_2()], then
//!   this is the "Normal case". In this case the input is split at the first occurrence
//!   of a special char in [get_sp_char_set_3()]. The "before" part is
//!   [MdLineFragment::Plain] and the "after" part is parsed again by a more specific
//!   parser.
//! - If the input starts with a special char in this [get_sp_char_set_2()] and it is not
//!   in the [get_sp_char_set_1()] with only 1 occurrence, then the behavior is different
//!   "Edge case -> Normal case". Otherwise the behavior is "Edge case -> Special case".
//!   - "Edge case -> Normal case" takes all the characters until `\n` or end of input and
//!     turns it into a [MdLineFragment::Plain].
//!   - "Edge case -> Special case" splits the `input` before and after the special char.
//!     The "before" part is turned into a [MdLineFragment::Plain] and the "after" part is
//!     parsed again by a more specific parser.
//!
//! The reason this parser gets called repeatedly is because it is the last one in the
//! chain. Its the lowest priority parser called by
//! [parse_inline_fragments_until_eol_or_eoi()], which itself is called:
//! 1. Repeatedly in a loop by [parse_block_markdown_text_with_or_without_new_line()].
//! 2. And by [parse_block_markdown_text_with_checkbox_policy_with_or_without_new_line()].

// External use.
pub mod atomics;
pub mod block;
pub mod convert_to_plain_text;
pub mod extended;
pub mod fragment;
pub mod md_parser_types;
pub mod parse_markdown;

pub use atomics::*;
pub use block::*;
pub use convert_to_plain_text::*;
pub use extended::*;
pub use fragment::*;
pub use md_parser_types::*;
pub use parse_markdown::*;