cmark_writer/writer/runtime/
proxy.rs

1use crate::ast::Node;
2use crate::error::{WriteError, WriteResult};
3use crate::options::WriterOptions;
4use crate::writer::cmark::CommonMarkWriter;
5use ecow::EcoString;
6
7/// Proxy that exposes a restricted API for block-level custom node rendering.
8pub struct BlockWriterProxy<'a> {
9    inner: &'a mut CommonMarkWriter,
10}
11
12impl<'a> BlockWriterProxy<'a> {
13    pub(crate) fn new(inner: &'a mut CommonMarkWriter) -> Self {
14        Self { inner }
15    }
16
17    /// Write a block-level node through the underlying writer.
18    pub fn write_block(&mut self, node: &Node) -> WriteResult<()> {
19        if !node.is_block() {
20            return Err(WriteError::InvalidStructure(
21                "Block writer expected a block-level node".into(),
22            ));
23        }
24        self.inner.write(node)
25    }
26
27    /// Write an inline node while remaining in a block context.
28    pub fn write_inline(&mut self, node: &Node) -> WriteResult<()> {
29        if node.is_block() {
30            return Err(WriteError::InvalidStructure(
31                "Inline content expected an inline node".into(),
32            ));
33        }
34        self.inner.write(node)
35    }
36
37    /// Write a collection of inline nodes.
38    pub fn write_inline_nodes(&mut self, nodes: &[Node]) -> WriteResult<()> {
39        for node in nodes {
40            self.write_inline(node)?;
41        }
42        Ok(())
43    }
44
45    /// Write raw text into the buffer.
46    pub fn write_str(&mut self, text: &str) -> WriteResult<()> {
47        self.inner.write_str(text)
48    }
49
50    /// Write a single character into the buffer.
51    pub fn write_char(&mut self, ch: char) -> WriteResult<()> {
52        self.inner.write_char(ch)
53    }
54
55    /// Ensure the buffer ends with a newline.
56    pub fn ensure_trailing_newline(&mut self) -> WriteResult<()> {
57        self.inner.ensure_trailing_newline()
58    }
59
60    /// Ensure there is a blank line at the end of the buffer.
61    pub fn ensure_blank_line(&mut self) -> WriteResult<()> {
62        self.inner.ensure_blank_line()
63    }
64
65    /// Capture the output produced inside the closure using a fresh block proxy.
66    pub fn capture_block<F>(&mut self, f: F) -> WriteResult<EcoString>
67    where
68        F: FnOnce(&mut BlockWriterProxy<'_>) -> WriteResult<()>,
69    {
70        self.inner.capture_with_buffer(|inner| {
71            let mut proxy = BlockWriterProxy::new(inner);
72            f(&mut proxy)
73        })
74    }
75
76    /// Capture output produced in an inline context.
77    pub fn capture_inline<F>(&mut self, f: F) -> WriteResult<EcoString>
78    where
79        F: FnOnce(&mut InlineWriterProxy<'_>) -> WriteResult<()>,
80    {
81        self.inner.capture_with_buffer(|inner| {
82            let mut proxy = InlineWriterProxy::new(inner);
83            f(&mut proxy)
84        })
85    }
86
87    /// Temporarily modify writer options while executing the provided closure.
88    pub fn with_temporary_options<F, R, G>(&mut self, modify: F, mut f: G) -> WriteResult<R>
89    where
90        F: FnOnce(&mut WriterOptions),
91        G: FnMut(&mut BlockWriterProxy<'_>) -> WriteResult<R>,
92    {
93        let original = self.inner.options.clone();
94        modify(&mut self.inner.options);
95        let result = f(self);
96        self.inner.options = original;
97        result
98    }
99}
100
101/// Proxy that exposes a restricted API for inline custom node rendering.
102pub struct InlineWriterProxy<'a> {
103    inner: &'a mut CommonMarkWriter,
104}
105
106impl<'a> InlineWriterProxy<'a> {
107    pub(crate) fn new(inner: &'a mut CommonMarkWriter) -> Self {
108        Self { inner }
109    }
110
111    /// Write an inline node through the underlying writer.
112    pub fn write_inline(&mut self, node: &Node) -> WriteResult<()> {
113        if node.is_block() {
114            return Err(WriteError::InvalidStructure(
115                "Inline writer cannot emit block-level nodes".into(),
116            ));
117        }
118        self.inner.write(node)
119    }
120
121    /// Write a collection of inline nodes.
122    pub fn write_inline_nodes(&mut self, nodes: &[Node]) -> WriteResult<()> {
123        for node in nodes {
124            self.write_inline(node)?;
125        }
126        Ok(())
127    }
128
129    /// Write raw text into the buffer.
130    pub fn write_str(&mut self, text: &str) -> WriteResult<()> {
131        self.inner.write_str(text)
132    }
133
134    /// Write a single character into the buffer.
135    pub fn write_char(&mut self, ch: char) -> WriteResult<()> {
136        self.inner.write_char(ch)
137    }
138
139    /// Capture inline output produced inside the closure.
140    pub fn capture_inline<F>(&mut self, f: F) -> WriteResult<EcoString>
141    where
142        F: FnOnce(&mut InlineWriterProxy<'_>) -> WriteResult<()>,
143    {
144        self.inner.capture_with_buffer(|inner| {
145            let mut proxy = InlineWriterProxy::new(inner);
146            f(&mut proxy)
147        })
148    }
149
150    /// Temporarily modify writer options while executing the provided closure.
151    pub fn with_temporary_options<F, R, G>(&mut self, modify: F, mut f: G) -> WriteResult<R>
152    where
153        F: FnOnce(&mut WriterOptions),
154        G: FnMut(&mut InlineWriterProxy<'_>) -> WriteResult<R>,
155    {
156        let original = self.inner.options.clone();
157        modify(&mut self.inner.options);
158        let result = f(self);
159        self.inner.options = original;
160        result
161    }
162}