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