use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Clone, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Code {
pub lang: String,
pub code: String,
}
impl Code {
pub fn new<S: Into<String>>(lang: S, code: S) -> Self {
let code = code.into();
let code = code.trim_end_matches('\n').to_owned();
Self {
lang: lang.into(),
code,
}
}
}
impl Display for Code {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"```{}\n{}\n```",
self.lang
.replace("\\", "\\\\")
.replace("`", "\\`")
.replace("\n", "\\\n"),
self.code.replace("\\", "\\\\").replace("```", "\\```")
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code() {
let code = Code::new("rust", "let a = 42;");
assert_eq!(code.to_string(), "```rust\nlet a = 42;\n```");
}
#[test]
fn code_with_backtick() {
let code = Code::new("rust", "let a = 42;\nlet ```b` = 43;");
assert_eq!(
code.to_string(),
"```rust\nlet a = 42;\nlet \\```b` = 43;\n```"
);
}
#[test]
fn language_with_eol() {
let code = Code::new("rust\n\n", "let a = 42;");
assert_eq!(code.to_string(), "```rust\\\n\\\n\nlet a = 42;\n```");
}
}