81 lines
3.1 KiB
Rust
81 lines
3.1 KiB
Rust
use syntect::easy::HighlightLines;
|
||
use syntect::highlighting::ThemeSet;
|
||
use syntect::html::{IncludeBackground, styled_line_to_highlighted_html};
|
||
use syntect::parsing::SyntaxSet;
|
||
|
||
/// Преобразует исходный код и его язык в подсвеченный HTML.
|
||
///
|
||
/// # Аргументы
|
||
/// * `code` - Исходный код как строка.
|
||
/// * `lang` - Идентификатор языка (например, "rust", "python", "mermaid").
|
||
/// * `ss` - Набор синтаксисов (SyntaxSet).
|
||
/// * `ts` - Набор тем (ThemeSet).
|
||
///
|
||
/// # Возвращает
|
||
/// Строку HTML, содержащую обертку блока кода с заголовком и кнопкой копирования.
|
||
pub fn code_to_html(code: &str, lang: &str, ss: &SyntaxSet, ts: &ThemeSet) -> String {
|
||
let theme = &ts.themes["base16-ocean.dark"];
|
||
|
||
if lang == "mermaid" {
|
||
let escaped_code = escape_html(code);
|
||
return format!(
|
||
r#"<div class="code-block-wrapper mermaid-wrapper">
|
||
<div class="code-header">
|
||
<span class="code-lang">Mermaid Diagram</span>
|
||
<button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
||
</div>
|
||
<div class="mermaid" style="background: transparent; padding: 20px; text-align: center;">{escaped_code}</div>
|
||
</div>"#
|
||
);
|
||
}
|
||
|
||
let lang_display = if lang.is_empty() { "text" } else { lang };
|
||
let lang_escaped = escape_html(lang_display);
|
||
|
||
let highlighted_html = if !lang.is_empty() {
|
||
if let Some(syntax) = ss.find_syntax_by_token(lang) {
|
||
let mut h = HighlightLines::new(syntax, theme);
|
||
let mut result_html = String::new();
|
||
|
||
for line in code.lines() {
|
||
let line_with_newline = format!("{line}\n");
|
||
|
||
match h.highlight_line(&line_with_newline, ss) {
|
||
Ok(regions) => {
|
||
match styled_line_to_highlighted_html(®ions[..], IncludeBackground::No) {
|
||
Ok(html_line) => result_html.push_str(&html_line),
|
||
Err(_) => result_html.push_str(&escape_html(&line_with_newline)),
|
||
}
|
||
}
|
||
Err(_) => {
|
||
result_html.push_str(&escape_html(&line_with_newline));
|
||
}
|
||
}
|
||
}
|
||
result_html
|
||
} else {
|
||
escape_html(code)
|
||
}
|
||
} else {
|
||
escape_html(code)
|
||
};
|
||
|
||
format!(
|
||
r#"<div class="code-block-wrapper">
|
||
<div class="code-header">
|
||
<span class="code-lang">{lang_escaped}</span>
|
||
<button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
||
</div>
|
||
<pre style="margin: 0; border-radius: 0 0 6px 6px;"><code>{highlighted_html}</code></pre>
|
||
</div>"#
|
||
)
|
||
}
|
||
|
||
fn escape_html(text: &str) -> String {
|
||
text.replace('&', "&")
|
||
.replace('<', "<")
|
||
.replace('>', ">")
|
||
.replace('"', """)
|
||
.replace('\'', "'")
|
||
}
|