cmark_writer/ast/
custom.rs

1//! Custom node definitions for the CommonMark AST.
2
3use crate::error::WriteResult;
4use crate::writer::{CommonMarkWriter, HtmlWriteResult, HtmlWriter};
5use std::any::Any;
6
7/// Trait for implementing custom node behavior for the CommonMark AST.
8///
9/// This trait defines methods that all custom node types must implement.
10/// Users can implement the `write` method for CommonMark output and
11/// optionally override the `html_write` method for HTML output.
12///
13/// The recommended way to implement this trait is through the `custom_node` macro,
14/// which provides a default implementation of most methods and requires users to
15/// implement only the node-specific logic.
16///
17/// # Example
18///
19/// ```rust
20/// use ecow::EcoString;
21/// use cmark_writer_macros::custom_node;
22/// use cmark_writer::CommonMarkWriter;
23/// use cmark_writer::writer::HtmlWriter;
24/// use cmark_writer::error::WriteResult;
25/// use cmark_writer::writer::HtmlWriteResult;
26///
27/// // Define a custom node with support for both CommonMark and HTML output
28/// #[derive(Debug, Clone, PartialEq)]
29/// #[custom_node(block=false, html_impl=true)]
30/// struct HighlightNode {
31///     content: EcoString,
32///     color: EcoString,
33/// }
34///
35/// impl HighlightNode {
36///     // Required for CommonMark output
37///     fn write_custom(&self, writer: &mut CommonMarkWriter) -> WriteResult<()> {
38///         writer.write_str("<span style=\"background-color: ")?;
39///         writer.write_str(&self.color)?;
40///         writer.write_str("\">")?;
41///         writer.write_str(&self.content)?;
42///         writer.write_str("</span>")?;
43///         Ok(())
44///     }
45///
46///     // Optional HTML-specific implementation
47///     fn write_html_custom(&self, writer: &mut HtmlWriter) -> HtmlWriteResult<()> {
48///         writer.start_tag("span")?;
49///         writer.attribute("style", &format!("background-color: {}", self.color))?;
50///         writer.finish_tag()?;
51///         writer.text(&self.content)?;
52///         writer.end_tag("span")?;
53///         Ok(())
54///     }
55/// }
56/// ```
57pub trait CustomNode: std::fmt::Debug + Send + Sync {
58    /// Write the custom node content to the CommonMarkWriter (for CommonMark output).
59    ///
60    /// When using the `custom_node` macro, this method delegates to the user-defined
61    /// `write_custom` method that must be implemented on the node type.
62    fn write(&self, writer: &mut CommonMarkWriter) -> WriteResult<()>;
63
64    /// Writes the HTML representation of the custom node to the provided HTML writer.
65    ///
66    /// By default, this writes an HTML comment indicating that HTML rendering is not implemented
67    /// for this custom node type. When using the `custom_node` macro with `html_impl=true`,
68    /// this method delegates to the user-defined `write_html_custom` method.
69    ///
70    /// Users should either:
71    /// 1. Override this method directly, or
72    /// 2. Use the `custom_node` macro with `html_impl=true` and implement the `write_html_custom` method.
73    fn html_write(&self, writer: &mut HtmlWriter) -> HtmlWriteResult<()> {
74        writer.raw_html(&format!(
75            "<!-- HTML rendering not implemented for Custom Node: {} -->",
76            self.type_name()
77        ))?;
78        Ok(())
79    }
80
81    /// Clone the custom node
82    fn clone_box(&self) -> Box<dyn CustomNode>;
83
84    /// Check if two custom nodes are equal
85    fn eq_box(&self, other: &dyn CustomNode) -> bool;
86
87    /// Whether the custom node is a block element
88    fn is_block(&self) -> bool;
89
90    /// Convert to Any for type casting
91    fn as_any(&self) -> &dyn Any;
92
93    /// Convert to mutable Any for type casting
94    fn as_any_mut(&mut self) -> &mut dyn Any;
95
96    /// Get the type name of the custom node for pattern matching
97    fn type_name(&self) -> &'static str {
98        std::any::type_name::<Self>()
99    }
100}
101
102// NOTE: CustomNodeWriter trait is deprecated and will be removed in a future version.
103// Custom nodes should now directly use CommonMarkWriter instead.
104/*
105/// Trait for custom node writer implementation
106pub trait CustomNodeWriter {
107    /// Write a string to the output
108    fn write_str(&mut self, s: &str) -> std::fmt::Result;
109
110    /// Write a character to the output
111    fn write_char(&mut self, c: char) -> std::fmt::Result;
112}
113*/
114
115// Implement Clone for Box<dyn CustomNode>
116impl Clone for Box<dyn CustomNode> {
117    fn clone(&self) -> Self {
118        self.clone_box()
119    }
120}
121
122// Implement PartialEq for Box<dyn CustomNode>
123impl PartialEq for Box<dyn CustomNode> {
124    fn eq(&self, other: &Self) -> bool {
125        self.eq_box(&**other)
126    }
127}