notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

partial.rs (3010B)


      1 //! Partial state tracking for incomplete markdown elements.
      2 
      3 use crate::element::Span;
      4 
      5 /// Tracks an in-progress markdown element that might be completed
      6 /// when more tokens arrive.
      7 #[derive(Debug, Clone)]
      8 pub struct Partial {
      9     /// What kind of element we're building
     10     pub kind: PartialKind,
     11 
     12     /// Byte offset into the buffer where this element starts
     13     pub start_pos: usize,
     14 
     15     /// Start of content region (after markers like "# ")
     16     pub content_start: usize,
     17 
     18     /// End of content accumulated so far
     19     pub content_end: usize,
     20 }
     21 
     22 impl Partial {
     23     pub fn new(kind: PartialKind, start_pos: usize) -> Self {
     24         Self {
     25             kind,
     26             start_pos,
     27             content_start: start_pos,
     28             content_end: start_pos,
     29         }
     30     }
     31 
     32     /// Get the content span
     33     pub fn content_span(&self) -> Span {
     34         Span::new(self.content_start, self.content_end)
     35     }
     36 
     37     /// Get the content as a string slice from the buffer
     38     pub fn content<'a>(&self, buffer: &'a str) -> &'a str {
     39         &buffer[self.content_start..self.content_end]
     40     }
     41 
     42     /// Check if content is empty
     43     pub fn content_is_empty(&self) -> bool {
     44         self.content_start == self.content_end
     45     }
     46 }
     47 
     48 /// The kind of partial element being tracked.
     49 #[derive(Debug, Clone, PartialEq)]
     50 pub enum PartialKind {
     51     /// Fenced code block waiting for closing ```
     52     /// Stores the fence info (backticks count, language)
     53     CodeFence {
     54         fence_char: char, // ` or ~
     55         fence_len: usize, // typically 3
     56         language: Option<Span>,
     57     },
     58 
     59     /// Inline code waiting for closing backtick(s)
     60     InlineCode { backtick_count: usize },
     61 
     62     /// Bold text waiting for closing ** or __
     63     Bold {
     64         marker: char, // * or _
     65     },
     66 
     67     /// Italic text waiting for closing * or _
     68     Italic { marker: char },
     69 
     70     /// Bold+italic waiting for closing *** or ___
     71     BoldItalic { marker: char },
     72 
     73     /// Strikethrough waiting for closing ~~
     74     Strikethrough,
     75 
     76     /// Link: seen [, waiting for ](url)
     77     /// States: text, post-bracket, url
     78     Link { state: LinkState, text: Span },
     79 
     80     /// Image: seen ![, waiting for ](url)
     81     Image { state: LinkState, alt: Span },
     82 
     83     /// Heading started with # at line start, collecting content
     84     Heading { level: u8 },
     85 
     86     /// List item started, collecting content
     87     ListItem {
     88         ordered: bool,
     89         number: Option<u32>,
     90         indent: usize,
     91     },
     92 
     93     /// Blockquote started with >, collecting content
     94     BlockQuote { depth: usize },
     95 
     96     /// Table being accumulated row by row
     97     Table {
     98         headers: Vec<Span>,
     99         rows: Vec<Vec<Span>>,
    100         seen_separator: bool,
    101     },
    102 
    103     /// Paragraph being accumulated (waiting for double newline)
    104     Paragraph,
    105 }
    106 
    107 /// State machine for link/image parsing.
    108 #[derive(Debug, Clone, PartialEq)]
    109 pub enum LinkState {
    110     /// Collecting text between [ and ]
    111     Text,
    112     /// Seen ], expecting (
    113     PostBracket,
    114     /// Collecting URL between ( and )
    115     Url(Span),
    116 }