Skip to main content

lex_core/lex/token/
inline.rs

1//! Inline token types and specifications
2//!
3//!     This module defines the token types for inline parsing. Inline elements are span-based
4//!     elements that can start and end at arbitrary positions within text content. Unlike the
5//!     line-based tokens (core and line), inline tokens operate at the character level and can
6//!     be nested within each other.
7//!
8//!     For the complete inline grammar specification, see specs/v1/grammar-inline.lex.
9//!
10//!     Related token modules:
11//!     - [core](super::core) - Character and word-level tokens from the logos lexer
12//!     - [line](super::line) - Line-based tokens for the main parser
13//!
14//! Inline Token Types
15//!
16//!     These are the inline element types supported by lex:
17//!
18//!         - Strong: *text* (bold/emphasis)
19//!         - Emphasis: _text_ (italic)
20//!         - Code: `text` (monospace, literal)
21//!         - Math: #formula# (mathematical notation, literal)
22//!         - Reference: [target] (links, citations, footnotes)
23//!
24//!     References support multiple subtypes including:
25//!         - Citations: [@key] or [@key1; @key2, pp. 42-45]
26//!         - Annotation references: [::label]
27//!         - Footnotes: [42]
28//!         - Session references: [#2.1]
29//!         - URLs: [https://example.com]
30//!         - File paths: [./path/to/file]
31//!         - TK placeholders: [TK] or [TK-identifier]
32//!         - General references: [Section Title]
33//!
34//!     Inline elements have these properties:
35//!     - Clear start and end markers (single character tokens)
36//!     - Can be nested (except literal types)
37//!     - Cannot break parent element boundaries
38//!     - No space allowed between marker and content
39//!
40//! Token Specifications
41//!
42//!     Each inline type is defined by an InlineSpec that specifies:
43//!     - The kind of inline element (from InlineKind enum)
44//!     - Start and end tokens (characters)
45//!     - Whether it's literal (no nested parsing inside)
46//!     - Optional post-processing callback for complex logic
47//!
48//! Citation Parsing
49//!
50//!     Citations are a specialized form of reference that follow academic citation format.
51//!     The reference token [target] is post-processed to detect citations starting with @.
52//!     Citation parsing is handled by [crate::lex::inlines::citations] which extracts:
53//!     - Multiple citation keys (separated by ; or ,)
54//!     - Optional page locators (p. or pp. followed by page ranges)
55//!     - Page ranges in various formats: single pages, ranges, or lists
56
57/// The type of inline element
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
59pub enum InlineKind {
60    /// Strong/bold text: *text*
61    Strong,
62    /// Emphasized/italic text: _text_
63    Emphasis,
64    /// Inline code: `text` (literal, no nested inlines)
65    Code,
66    /// Mathematical notation: #formula# (literal, no nested inlines)
67    Math,
68    /// Reference (link, citation, footnote): \[target\] (literal, no nested inlines)
69    Reference,
70}
71
72impl std::fmt::Display for InlineKind {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        match self {
75            InlineKind::Strong => write!(f, "strong"),
76            InlineKind::Emphasis => write!(f, "emphasis"),
77            InlineKind::Code => write!(f, "code"),
78            InlineKind::Math => write!(f, "math"),
79            InlineKind::Reference => write!(f, "reference"),
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_inline_kind_display() {
90        assert_eq!(format!("{}", InlineKind::Strong), "strong");
91        assert_eq!(format!("{}", InlineKind::Emphasis), "emphasis");
92        assert_eq!(format!("{}", InlineKind::Code), "code");
93        assert_eq!(format!("{}", InlineKind::Math), "math");
94        assert_eq!(format!("{}", InlineKind::Reference), "reference");
95    }
96
97    #[test]
98    fn test_inline_kind_equality() {
99        assert_eq!(InlineKind::Strong, InlineKind::Strong);
100        assert_ne!(InlineKind::Strong, InlineKind::Emphasis);
101        assert_ne!(InlineKind::Code, InlineKind::Math);
102    }
103}