atproto blogging
1use super::{FacetFeature, FacetOutput};
2use std::fmt::Write;
3
4pub struct HtmlFacetOutput<W: Write> {
5 writer: W,
6}
7
8impl<W: Write> HtmlFacetOutput<W> {
9 pub fn new(writer: W) -> Self {
10 Self { writer }
11 }
12
13 pub fn into_inner(self) -> W {
14 self.writer
15 }
16}
17
18impl<W: Write> FacetOutput for HtmlFacetOutput<W> {
19 type Error = std::fmt::Error;
20
21 fn write_text(&mut self, text: &str) -> Result<(), Self::Error> {
22 for c in text.chars() {
23 match c {
24 '&' => self.writer.write_str("&")?,
25 '<' => self.writer.write_str("<")?,
26 '>' => self.writer.write_str(">")?,
27 _ => self.writer.write_char(c)?,
28 }
29 }
30 Ok(())
31 }
32
33 fn start_feature(&mut self, feature: &FacetFeature<'_>) -> Result<(), Self::Error> {
34 match feature {
35 FacetFeature::Bold => write!(self.writer, "<strong>"),
36 FacetFeature::Italic => write!(self.writer, "<em>"),
37 FacetFeature::Code => write!(self.writer, "<code>"),
38 FacetFeature::Underline => write!(self.writer, "<u>"),
39 FacetFeature::Strikethrough => write!(self.writer, "<s>"),
40 FacetFeature::Highlight => write!(self.writer, "<mark>"),
41 FacetFeature::Link { uri } => {
42 write!(self.writer, "<a href=\"")?;
43 for c in uri.chars() {
44 match c {
45 '"' => self.writer.write_str("%22")?,
46 _ => self.writer.write_char(c)?,
47 }
48 }
49 write!(self.writer, "\">")
50 }
51 FacetFeature::DidMention { did } => {
52 write!(
53 self.writer,
54 "<a class=\"mention\" href=\"https://bsky.app/profile/{}\">",
55 did
56 )
57 }
58 FacetFeature::AtMention { at_uri } => {
59 write!(self.writer, "<a class=\"at-mention\" href=\"{}\">", at_uri)
60 }
61 FacetFeature::Tag { tag } => {
62 write!(
63 self.writer,
64 "<a class=\"hashtag\" href=\"https://bsky.app/hashtag/{}\">",
65 tag
66 )
67 }
68 FacetFeature::Id { id } => {
69 if let Some(id) = id {
70 write!(self.writer, "<span id=\"{}\">", id)
71 } else {
72 write!(self.writer, "<span>")
73 }
74 }
75 }
76 }
77
78 fn end_feature(&mut self, feature: &FacetFeature<'_>) -> Result<(), Self::Error> {
79 match feature {
80 FacetFeature::Bold => write!(self.writer, "</strong>"),
81 FacetFeature::Italic => write!(self.writer, "</em>"),
82 FacetFeature::Code => write!(self.writer, "</code>"),
83 FacetFeature::Underline => write!(self.writer, "</u>"),
84 FacetFeature::Strikethrough => write!(self.writer, "</s>"),
85 FacetFeature::Highlight => write!(self.writer, "</mark>"),
86 FacetFeature::Link { .. }
87 | FacetFeature::DidMention { .. }
88 | FacetFeature::AtMention { .. }
89 | FacetFeature::Tag { .. } => write!(self.writer, "</a>"),
90 FacetFeature::Id { .. } => write!(self.writer, "</span>"),
91 }
92 }
93}
94
95pub fn render_faceted_html(
96 text: &str,
97 facets: &[super::NormalizedFacet<'_>],
98) -> Result<String, std::fmt::Error> {
99 let mut output = HtmlFacetOutput::new(String::new());
100 super::process_faceted_text(text, facets, &mut output)?;
101 Ok(output.into_inner())
102}