fix(copy-button): fix copy code button
This commit is contained in:
parent
b1114217e0
commit
f15e8166d1
@ -27,7 +27,7 @@ repos:
|
|||||||
- id: clippy
|
- id: clippy
|
||||||
name: clippy
|
name: clippy
|
||||||
language: system
|
language: system
|
||||||
entry: cargo clippy -- -W clippy::all -W clippy::pedantic
|
entry: cargo clippy -- -D clippy::all -D clippy::pedantic
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
always_run: true
|
always_run: true
|
||||||
|
|
||||||
|
|||||||
2
TODO.md
2
TODO.md
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
* [X] ~~Сделать кнопку скопировать путь~~
|
* [X] ~~Сделать кнопку скопировать путь~~
|
||||||
* [X] ~~Сделать кнопку скопировать путь вместе с командой (`note edit ...`)~~
|
* [X] ~~Сделать кнопку скопировать путь вместе с командой (`note edit ...`)~~
|
||||||
|
* [X] ~~Сделать отображение типа кода и кнопку скопировать код~~
|
||||||
|
* [ ] Починить заголовки таблицы
|
||||||
|
|||||||
62
src/main.rs
62
src/main.rs
@ -28,7 +28,6 @@ use syntect::parsing::SyntaxSet;
|
|||||||
|
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
use webbrowser;
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -152,10 +151,8 @@ async fn main() {
|
|||||||
|
|
||||||
if args.browser {
|
if args.browser {
|
||||||
let mut url = format!("http://{actual_addr}");
|
let mut url = format!("http://{actual_addr}");
|
||||||
if args.random {
|
if args.random && !state.is_root_file {
|
||||||
if !state.is_root_file {
|
url = format!("{url}/random");
|
||||||
url = format!("{url}/random")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let _ = webbrowser::open(url.as_str());
|
let _ = webbrowser::open(url.as_str());
|
||||||
}
|
}
|
||||||
@ -185,12 +182,9 @@ async fn root_handler(State(state): State<AppState>) -> impl IntoResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn render_single_file(
|
async fn render_single_file(file_path: &StdPath) -> Result<NoteTemplate, StatusCode> {
|
||||||
file_path: &StdPath,
|
let Ok(metadata) = fs::metadata(file_path).await else {
|
||||||
) -> Result<NoteTemplate, StatusCode> {
|
return Err(StatusCode::NOT_FOUND);
|
||||||
let metadata = match fs::metadata(file_path).await {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(_) => return Err(StatusCode::NOT_FOUND),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
@ -203,9 +197,8 @@ async fn render_single_file(
|
|||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
||||||
let content = match fs::read_to_string(file_path).await {
|
let Ok(content) = fs::read_to_string(file_path).await else {
|
||||||
Ok(c) => c,
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let display_path = "";
|
let display_path = "";
|
||||||
@ -216,12 +209,7 @@ async fn render_single_file(
|
|||||||
let html_content = if extension == "md" {
|
let html_content = if extension == "md" {
|
||||||
markdown_to_html(&content, display_path)
|
markdown_to_html(&content, display_path)
|
||||||
} else {
|
} else {
|
||||||
code_to_html(
|
code_to_html(&content, extension.as_str(), &ss, &ts)
|
||||||
&content,
|
|
||||||
extension.as_str(),
|
|
||||||
&ss,
|
|
||||||
&ts,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let filename = file_path
|
let filename = file_path
|
||||||
@ -275,9 +263,8 @@ async fn serve_file(
|
|||||||
return Err(StatusCode::FORBIDDEN);
|
return Err(StatusCode::FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = match fs::metadata(&safe_path).await {
|
let Ok(metadata) = fs::metadata(&safe_path).await else {
|
||||||
Ok(m) => m,
|
return Err(StatusCode::NOT_FOUND);
|
||||||
Err(_) => return Err(StatusCode::NOT_FOUND),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
@ -299,17 +286,15 @@ async fn serve_file(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if is_image {
|
if is_image {
|
||||||
let file_content = match fs::read(&safe_path).await {
|
let Ok(file_content) = fs::read(&safe_path).await else {
|
||||||
Ok(content) => content,
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
||||||
};
|
};
|
||||||
let mime_type = from_path(&safe_path).first_or_octet_stream();
|
let mime_type = from_path(&safe_path).first_or_octet_stream();
|
||||||
return Ok(([(header::CONTENT_TYPE, mime_type.as_ref())], file_content).into_response());
|
return Ok(([(header::CONTENT_TYPE, mime_type.as_ref())], file_content).into_response());
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = match fs::read_to_string(&safe_path).await {
|
let Ok(content) = fs::read_to_string(&safe_path).await else {
|
||||||
Ok(c) => c,
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ss = SyntaxSet::load_defaults_newlines();
|
let ss = SyntaxSet::load_defaults_newlines();
|
||||||
@ -318,12 +303,7 @@ async fn serve_file(
|
|||||||
let html_content = if extension == "md" {
|
let html_content = if extension == "md" {
|
||||||
markdown_to_html(&content, &full_path)
|
markdown_to_html(&content, &full_path)
|
||||||
} else {
|
} else {
|
||||||
code_to_html(
|
code_to_html(&content, extension.as_str(), &ss, &ts)
|
||||||
&content,
|
|
||||||
extension.as_str(),
|
|
||||||
&ss,
|
|
||||||
&ts,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let filename = safe_path
|
let filename = safe_path
|
||||||
@ -365,9 +345,8 @@ async fn render_directory_index(
|
|||||||
dir_path: &StdPath,
|
dir_path: &StdPath,
|
||||||
request_path: &str,
|
request_path: &str,
|
||||||
) -> Result<DirectoryTemplate, StatusCode> {
|
) -> Result<DirectoryTemplate, StatusCode> {
|
||||||
let mut entries = match fs::read_dir(dir_path).await {
|
let Ok(mut entries) = fs::read_dir(dir_path).await else {
|
||||||
Ok(list) => list,
|
return Err(StatusCode::FORBIDDEN);
|
||||||
Err(_) => return Err(StatusCode::FORBIDDEN),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut files: Vec<FileEntry> = Vec::new();
|
let mut files: Vec<FileEntry> = Vec::new();
|
||||||
@ -388,7 +367,7 @@ async fn render_directory_index(
|
|||||||
let link = if request_path.is_empty() {
|
let link = if request_path.is_empty() {
|
||||||
file_name.clone()
|
file_name.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("{}/{}", request_path, file_name)
|
format!("{request_path}/{file_name}")
|
||||||
};
|
};
|
||||||
|
|
||||||
files.push(FileEntry {
|
files.push(FileEntry {
|
||||||
@ -513,9 +492,8 @@ async fn random_file(State(state): State<AppState>) -> impl IntoResponse {
|
|||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let random_path = files.choose(&mut rng).unwrap();
|
let random_path = files.choose(&mut rng).unwrap();
|
||||||
|
|
||||||
let relative_path = match random_path.strip_prefix(&state.root) {
|
let Ok(relative_path) = random_path.strip_prefix(&state.root) else {
|
||||||
Ok(p) => p,
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let url_path = relative_path.to_string_lossy().replace('\\', "/");
|
let url_path = relative_path.to_string_lossy().replace('\\', "/");
|
||||||
|
|||||||
148
src/markdown.rs
148
src/markdown.rs
@ -3,6 +3,8 @@ use pulldown_cmark::{
|
|||||||
TextMergeStream,
|
TextMergeStream,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub fn markdown_to_html(markdown: &str, _file_path: &str) -> String {
|
pub fn markdown_to_html(markdown: &str, _file_path: &str) -> String {
|
||||||
let mut options = Options::empty();
|
let mut options = Options::empty();
|
||||||
options.insert(Options::ENABLE_TABLES);
|
options.insert(Options::ENABLE_TABLES);
|
||||||
@ -51,21 +53,21 @@ pub fn markdown_to_html(markdown: &str, _file_path: &str) -> String {
|
|||||||
Event::Code(code) => {
|
Event::Code(code) => {
|
||||||
html_output.push_str(format!("<code>{}</code>", escape_html(&code)).as_str());
|
html_output.push_str(format!("<code>{}</code>", escape_html(&code)).as_str());
|
||||||
}
|
}
|
||||||
Event::SoftBreak => html_output.push_str(" "),
|
Event::SoftBreak => html_output.push(' '),
|
||||||
Event::HardBreak => html_output.push_str("<br>"),
|
Event::HardBreak => html_output.push_str("<br>"),
|
||||||
|
|
||||||
Event::Html(html) => html_output.push_str(&html),
|
Event::Html(html) => html_output.push_str(&html),
|
||||||
|
|
||||||
Event::Rule => html_output.push_str("<hr>"),
|
Event::Rule => html_output.push_str("<hr>"),
|
||||||
|
|
||||||
Event::FootnoteReference(fref) => html_output.push_str(&format!(
|
Event::FootnoteReference(fref) => {
|
||||||
"<sup><a href=\"#{}\" id=\"{}\"></a></sup>",
|
let _ = write!(
|
||||||
fref, fref
|
html_output,
|
||||||
)),
|
"<sup><a href=\"#{fref}\" id=\"{fref}\"></a></sup>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Event::InlineHtml(_) => (),
|
Event::InlineHtml(_) | Event::InlineMath(_) | Event::DisplayMath(_) => (),
|
||||||
Event::InlineMath(_) => (),
|
|
||||||
Event::DisplayMath(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,31 +96,30 @@ fn render_start_tag(tag: Tag<'_>) -> String {
|
|||||||
dest_url,
|
dest_url,
|
||||||
title,
|
title,
|
||||||
..
|
..
|
||||||
} => output.push_str(render_link(link_type, dest_url, title).as_str()),
|
} => output.push_str(render_link(link_type, &dest_url, &title).as_str()),
|
||||||
Tag::Image {
|
Tag::Image {
|
||||||
link_type,
|
link_type,
|
||||||
dest_url,
|
dest_url,
|
||||||
title,
|
title,
|
||||||
..
|
..
|
||||||
} => output.push_str(render_image(link_type, dest_url, title).as_str()),
|
} => output.push_str(render_image(link_type, &dest_url, &title).as_str()),
|
||||||
|
|
||||||
Tag::Table(_) => output.push_str("<table>"), // TODO: fix table
|
Tag::Table(_) => output.push_str("<table>"),
|
||||||
Tag::TableHead => output.push_str("<thead>"),
|
Tag::TableHead => output.push_str("<thead>"),
|
||||||
Tag::TableCell => output.push_str("<td>"),
|
Tag::TableCell => output.push_str("<td>"),
|
||||||
Tag::TableRow => output.push_str("<tr>"),
|
Tag::TableRow => output.push_str("<tr>"),
|
||||||
|
|
||||||
Tag::HtmlBlock => (), // TODO: implement
|
|
||||||
|
|
||||||
Tag::FootnoteDefinition(fref) => {
|
Tag::FootnoteDefinition(fref) => {
|
||||||
output.push_str(&format!("<sup><a href=\"#{}\" id=\"{}\">", fref, fref))
|
let _ = write!(output, "<sup><a href=\"#{fref}\" id=\"{fref}\">");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag::DefinitionList => (),
|
Tag::HtmlBlock
|
||||||
Tag::DefinitionListTitle => (),
|
| Tag::DefinitionList
|
||||||
Tag::DefinitionListDefinition => (),
|
| Tag::DefinitionListTitle
|
||||||
Tag::Superscript => (),
|
| Tag::DefinitionListDefinition
|
||||||
Tag::Subscript => (),
|
| Tag::Superscript
|
||||||
Tag::MetadataBlock(_) => (),
|
| Tag::Subscript
|
||||||
|
| Tag::MetadataBlock(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
@ -137,7 +138,7 @@ fn render_end_tag(tag: TagEnd) -> String {
|
|||||||
TagEnd::List(false) => output.push_str("</ul>"),
|
TagEnd::List(false) => output.push_str("</ul>"),
|
||||||
TagEnd::Item => output.push_str("</li>"),
|
TagEnd::Item => output.push_str("</li>"),
|
||||||
TagEnd::Paragraph => output.push_str("</p>"),
|
TagEnd::Paragraph => output.push_str("</p>"),
|
||||||
TagEnd::CodeBlock => output.push_str("</code></pre>"),
|
TagEnd::CodeBlock => output.push_str("</code></pre></div>"),
|
||||||
TagEnd::Emphasis => output.push_str("</em>"),
|
TagEnd::Emphasis => output.push_str("</em>"),
|
||||||
TagEnd::Strong => output.push_str("</strong>"),
|
TagEnd::Strong => output.push_str("</strong>"),
|
||||||
TagEnd::BlockQuote(_) => output.push_str("</blockquote>"),
|
TagEnd::BlockQuote(_) => output.push_str("</blockquote>"),
|
||||||
@ -150,78 +151,81 @@ fn render_end_tag(tag: TagEnd) -> String {
|
|||||||
TagEnd::TableRow => output.push_str("</tr>"),
|
TagEnd::TableRow => output.push_str("</tr>"),
|
||||||
|
|
||||||
TagEnd::FootnoteDefinition => output.push_str("</a></sup>"),
|
TagEnd::FootnoteDefinition => output.push_str("</a></sup>"),
|
||||||
TagEnd::HtmlBlock => (), // TODO: implement
|
|
||||||
|
|
||||||
TagEnd::DefinitionList => (),
|
TagEnd::HtmlBlock
|
||||||
TagEnd::DefinitionListTitle => (),
|
| TagEnd::DefinitionList
|
||||||
TagEnd::DefinitionListDefinition => (),
|
| TagEnd::DefinitionListTitle
|
||||||
TagEnd::Superscript => (),
|
| TagEnd::DefinitionListDefinition
|
||||||
TagEnd::Subscript => (),
|
| TagEnd::Superscript
|
||||||
TagEnd::MetadataBlock(_) => (),
|
| TagEnd::Subscript
|
||||||
|
| TagEnd::MetadataBlock(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_codeblock(block_kind: CodeBlockKind<'_>) -> String {
|
fn render_codeblock(block_kind: CodeBlockKind<'_>) -> String {
|
||||||
|
let header = String::from(
|
||||||
|
r#"
|
||||||
|
<div class="code-block-wrapper">
|
||||||
|
<div class="code-header">
|
||||||
|
<span class="code-lang">%CODE%</span> <button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
||||||
|
</div>
|
||||||
|
<pre>"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
match block_kind {
|
match block_kind {
|
||||||
CodeBlockKind::Indented => "<pre><code>".to_string(),
|
CodeBlockKind::Indented => {
|
||||||
|
output.push_str(&header.replace("%CODE%", "code"));
|
||||||
|
output.push_str("<code>");
|
||||||
|
}
|
||||||
|
|
||||||
CodeBlockKind::Fenced(CowStr::Borrowed("mermaid")) => {
|
CodeBlockKind::Fenced(CowStr::Borrowed("mermaid")) => {
|
||||||
"<pre><code class=\"language-text mermaid\">".to_string()
|
output.push_str(&header.replace("%CODE%", "mermaid"));
|
||||||
|
output.push_str("<code class=\"language-text mermaid\">");
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeBlockKind::Fenced(CowStr::Borrowed("rawmermaid")) => {
|
CodeBlockKind::Fenced(CowStr::Borrowed("rawmermaid")) => {
|
||||||
"<pre><code class=\"language-text\">".to_string()
|
output.push_str(&header.replace("%CODE%", "mermaid"));
|
||||||
|
output.push_str("<code class=\"language-text\">");
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeBlockKind::Fenced(code_type) => {
|
||||||
|
output.push_str(&header.replace("%CODE%", &code_type));
|
||||||
|
output.push_str(format!("<code class=\"language-{code_type}\">").as_str());
|
||||||
}
|
}
|
||||||
CodeBlockKind::Fenced(code_type) => format!("<pre><code class=\"language-{}\">", code_type),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_blockquote(quote_kind: Option<BlockQuoteKind>) -> String {
|
fn render_blockquote(quote_kind: Option<BlockQuoteKind>) -> String {
|
||||||
match quote_kind {
|
let alert_class_and_title = match quote_kind {
|
||||||
None => {
|
None => return "<blockquote>".to_string(),
|
||||||
"<blockquote>".to_string()
|
Some(BlockQuoteKind::Note) => ("note", "Note"),
|
||||||
},
|
Some(BlockQuoteKind::Tip) => ("tip", "Tip"),
|
||||||
Some(BlockQuoteKind::Note) => "<blockquote><div class=\"markdown-alert markdown-alert-note\"><p class=\"markdown-alert-title\">Note</p>".to_string(),
|
Some(BlockQuoteKind::Important) => ("important", "Important"),
|
||||||
Some(BlockQuoteKind::Tip) => "<blockquote><div class=\"markdown-alert markdown-alert-tip\"><p class=\"markdown-alert-title\">Tip</p>".to_string(),
|
Some(BlockQuoteKind::Warning) => ("warning", "Warning"),
|
||||||
Some(BlockQuoteKind::Important) =>"<blockquote><div class=\"markdown-alert markdown-alert-important\"><p class=\"markdown-alert-title\">Important</p>".to_string(),
|
Some(BlockQuoteKind::Caution) => ("caution", "Caution"),
|
||||||
Some(BlockQuoteKind::Warning) => "<blockquote><div class=\"markdown-alert markdown-alert-warning\"><p class=\"markdown-alert-title\">Warning</p>".to_string(),
|
};
|
||||||
Some(BlockQuoteKind::Caution) => "<blockquote><div class=\"markdown-alert markdown-alert-caution\"><p class=\"markdown-alert-title\">Caution</p>".to_string(),
|
|
||||||
}
|
format!(
|
||||||
|
"<blockquote><div class=\"markdown-alert markdown-alert-{}\"><p class=\"markdown-alert-title\">{}</p>",
|
||||||
|
alert_class_and_title.0, alert_class_and_title.1
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn render_link(link_type: LinkType, dest_url: CowStr<'_>, title: CowStr<'_>) -> String {
|
|
||||||
|
fn render_link(link_type: LinkType, dest_url: &CowStr<'_>, title: &CowStr<'_>) -> String {
|
||||||
match link_type {
|
match link_type {
|
||||||
LinkType::Inline => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
LinkType::Email => format!("<a href=\"mailto:{dest_url}\" title=\"{title}\">"),
|
||||||
LinkType::Reference => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
_ => format!("<a href=\"{dest_url}\" title=\"{title}\">"),
|
||||||
LinkType::ReferenceUnknown => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Collapsed => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::CollapsedUnknown => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Shortcut => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::ShortcutUnknown => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Autolink => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Email => format!("<a href=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::WikiLink { has_pothole: _ } => {
|
|
||||||
// TODO: refactor
|
|
||||||
format!("<a href=\"{}\" title=\"{}\">", dest_url, title)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_image(link_type: LinkType, dest_url: CowStr<'_>, title: CowStr<'_>) -> String {
|
fn render_image(_link_type: LinkType, dest_url: &CowStr<'_>, title: &CowStr<'_>) -> String {
|
||||||
match link_type {
|
format!("<img src=\"{dest_url}\" alt=\"{title}\">")
|
||||||
LinkType::Inline => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Reference => format!("<img src=\"{}\" title=\"{}\">", dest_url, title),
|
|
||||||
LinkType::ReferenceUnknown => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Collapsed => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::CollapsedUnknown => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Shortcut => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::ShortcutUnknown => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Autolink => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::Email => format!("<img src=\"{}\" alt=\"{}\">", dest_url, title),
|
|
||||||
LinkType::WikiLink { has_pothole: _ } => {
|
|
||||||
// TODO: refactor
|
|
||||||
format!("<img src=\"{}\" alt=\"{}\">", dest_url, title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape_html(text: &str) -> String {
|
fn escape_html(text: &str) -> String {
|
||||||
|
|||||||
38
src/other.rs
38
src/other.rs
@ -8,8 +8,8 @@ use syntect::parsing::SyntaxSet;
|
|||||||
/// # Аргументы
|
/// # Аргументы
|
||||||
/// * `code` - Исходный код как строка.
|
/// * `code` - Исходный код как строка.
|
||||||
/// * `lang` - Идентификатор языка (например, "rust", "python", "mermaid").
|
/// * `lang` - Идентификатор языка (например, "rust", "python", "mermaid").
|
||||||
/// * `ss` - Набор синтаксисов (SyntaxSet).
|
/// * `ss` - Набор синтаксисов (`SyntaxSet`).
|
||||||
/// * `ts` - Набор тем (ThemeSet).
|
/// * `ts` - Набор тем (`ThemeSet`).
|
||||||
///
|
///
|
||||||
/// # Возвращает
|
/// # Возвращает
|
||||||
/// Строку HTML, содержащую обертку блока кода с заголовком и кнопкой копирования.
|
/// Строку HTML, содержащую обертку блока кода с заголовком и кнопкой копирования.
|
||||||
@ -32,30 +32,28 @@ pub fn code_to_html(code: &str, lang: &str, ss: &SyntaxSet, ts: &ThemeSet) -> St
|
|||||||
let lang_display = if lang.is_empty() { "text" } else { lang };
|
let lang_display = if lang.is_empty() { "text" } else { lang };
|
||||||
let lang_escaped = escape_html(lang_display);
|
let lang_escaped = escape_html(lang_display);
|
||||||
|
|
||||||
let highlighted_html = if !lang.is_empty() {
|
let highlighted_html = if lang.is_empty() {
|
||||||
if let Some(syntax) = ss.find_syntax_by_token(lang) {
|
escape_html(code)
|
||||||
let mut h = HighlightLines::new(syntax, theme);
|
} else if let Some(syntax) = ss.find_syntax_by_token(lang) {
|
||||||
let mut result_html = String::new();
|
let mut h = HighlightLines::new(syntax, theme);
|
||||||
|
let mut result_html = String::new();
|
||||||
|
|
||||||
for line in code.lines() {
|
for line in code.lines() {
|
||||||
let line_with_newline = format!("{line}\n");
|
let line_with_newline = format!("{line}\n");
|
||||||
|
|
||||||
match h.highlight_line(&line_with_newline, ss) {
|
match h.highlight_line(&line_with_newline, ss) {
|
||||||
Ok(regions) => {
|
Ok(regions) => {
|
||||||
match styled_line_to_highlighted_html(®ions[..], IncludeBackground::No) {
|
match styled_line_to_highlighted_html(®ions[..], IncludeBackground::No) {
|
||||||
Ok(html_line) => result_html.push_str(&html_line),
|
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)),
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
result_html
|
||||||
} else {
|
} else {
|
||||||
escape_html(code)
|
escape_html(code)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,6 +55,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #2b303b;
|
background-color: #2b303b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-header {
|
.code-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user