1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

Implement a to_html method for FormattedText

Also fix a small issue with ansi formatting where it duplicated
text.
This commit is contained in:
Kumpelinus 2025-03-10 13:07:16 +01:00
parent 4a7d21425c
commit df5ae7ebbe
2 changed files with 88 additions and 1 deletions

View file

@ -107,7 +107,10 @@ impl FormattedText {
for component in self.clone().into_iter() {
let component_text = match &component {
Self::Text(c) => c.text.to_string(),
Self::Translatable(c) => c.to_string(),
Self::Translatable(c) => match c.read() {
Ok(c) => c.to_string(),
Err(_) => c.key.to_string(),
},
};
let component_style = &component.get_base().style;
@ -125,6 +128,50 @@ impl FormattedText {
built_string
}
pub fn to_html(&self) -> String {
// default the default_style to white if it's not set
self.to_html_with_custom_style(&DEFAULT_STYLE)
}
pub fn to_html_with_custom_style(&self, default_style: &Style) -> String {
let mut html_output = String::new();
let mut running_style = default_style.clone();
for component in self.clone().into_iter() {
let component_style = &component.get_base().style;
// Calculate the effective style by merging the running style with the component's style.
let effective_style = running_style.merged_with(component_style);
let style_string = effective_style.get_html_style();
// Get the component text and replace newlines with <br>
let component_text = match &component {
Self::Text(c) => c.text.to_string(),
Self::Translatable(c) => match c.read() {
Ok(text) => text.to_string(),
Err(_) => c.key.to_string(),
},
}.replace("\n", "<br>");
// Append the styled span for this component.
html_output.push_str(&format!(
"<span style=\"{}\">{}</span>",
style_string, component_text
));
// Update the running style:
// If the component requests a reset, revert to default.
if component_style.reset {
running_style = default_style.clone();
} else {
running_style.apply(component_style);
}
}
html_output
}
}
impl IntoIterator for FormattedText {

View file

@ -559,6 +559,20 @@ impl Style {
}
}
/// Returns a new style that is a merge of self and other.
/// For any field that `other` does not specify (is None), selfs value is used.
pub fn merged_with(&self, other: &Style) -> Style {
Style {
color: other.color.clone().or(self.color.clone()),
bold: other.bold.or(self.bold),
italic: other.italic.or(self.italic),
underlined: other.underlined.or(self.underlined),
strikethrough: other.strikethrough.or(self.strikethrough),
obfuscated: other.obfuscated.or(self.obfuscated),
reset: other.reset, // if reset is true in the new style, that takes precedence
}
}
/// Apply a ChatFormatting to this style
pub fn apply_formatting(&mut self, formatting: &ChatFormatting) {
match *formatting {
@ -576,6 +590,32 @@ impl Style {
}
}
}
pub fn get_html_style(&self) -> String {
let mut style = String::new();
if let Some(color) = &self.color {
style.push_str(&format!("color: {};", color.format_value()));
}
if let Some(bold) = self.bold {
style.push_str(&format!("font-weight: {};", if bold { "bold" } else { "normal" }));
}
if let Some(italic) = self.italic {
style.push_str(&format!("font-style: {};", if italic { "italic" } else { "normal" }));
}
if let Some(underlined) = self.underlined {
style.push_str(&format!("text-decoration: {};", if underlined { "underline" } else { "none" }));
}
if let Some(strikethrough) = self.strikethrough {
style.push_str(&format!("text-decoration: {};", if strikethrough { "line-through" } else { "none" }));
}
if let Some(obfuscated) = self.obfuscated {
if obfuscated {
style.push_str("filter: blur(2px);");
}
}
style
}
}
#[cfg(feature = "simdnbt")]