diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 696987a..779a10b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -27,14 +27,14 @@ repos:
- id: clippy
name: clippy
language: system
- entry: cargo clippy
+ entry: cargo clippy -- -W clippy::all -W clippy::pedantic
pass_filenames: false
always_run: true
- id: cargo-fmt
name: cargo fmt
language: system
- entry: cargo fmt
+ entry: cargo fmt --check
pass_filenames: false
always_run: true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..1566389
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+# Contributing Guide
+
+## Commit message format
+We use [this](https://www.conventionalcommits.org/en/v1.0.0/) standard
+```gitcommit
+():
+
+[optional body]
+
+[optional footer]
+```
+
+## Setting Up Pre-Commit Hooks
+We use pre-commit to automatically enforce code quality checks before commits:
+```sh
+python3 -m venv venv
+. ./venv/bin/activate
+pip install pre-commit
+pre-commit install
+pre-commit install --hook-type commit-msg
+```
+Hooks will now run automatically on every commit.
diff --git a/src/main.rs b/src/main.rs
index 67f0482..545bd05 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,7 @@ use futures::StreamExt;
use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use pulldown_cmark::{CodeBlockKind, Event, Options, Tag, html};
use std::convert::Infallible;
+use std::fmt::Write;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::PathBuf;
use std::sync::Arc;
@@ -97,14 +98,14 @@ async fn main() {
let addr = resolve_addr(&args.host, args.port).unwrap();
- println!("Сервер запущен на http://{}", addr);
+ println!("Сервер запущен на http://{addr}");
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
fn resolve_addr(host: &str, port: u16) -> io::Result {
- let addr_str = format!("{}:{}", host, port);
+ let addr_str = format!("{host}:{port}");
addr_str
.to_socket_addrs()?
@@ -178,25 +179,26 @@ async fn serve_file(
requested_path.push(&full_path);
// Безопасность путей
- let safe_path = match fs::canonicalize(&requested_path).await {
- Ok(p) => p,
- Err(_) => return Err(StatusCode::NOT_FOUND),
+ let Ok(safe_path) = fs::canonicalize(&requested_path).await else {
+ return Err(StatusCode::NOT_FOUND);
};
- let base_dir = match fs::canonicalize(&state.root).await {
- Ok(p) => p,
- Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
+ let Ok(base_dir) = fs::canonicalize(&state.root).await else {
+ return Err(StatusCode::INTERNAL_SERVER_ERROR);
};
if !safe_path.starts_with(&base_dir) {
- eprintln!("Попытка выхода за пределы директории: {:?}", safe_path);
+ eprintln!(
+ "Попытка выхода за пределы директории: {}",
+ safe_path.display()
+ );
return Err(StatusCode::FORBIDDEN);
}
let metadata = match fs::metadata(&safe_path).await {
Ok(m) => m,
Err(e) => {
- eprintln!("Ошибка получения метаданных: {}", e);
+ eprintln!("Ошибка получения метаданных: {e}");
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
};
@@ -208,7 +210,7 @@ async fn serve_file(
let content = match fs::read_to_string(&safe_path).await {
Ok(c) => c,
Err(e) => {
- eprintln!("Ошибка чтения: {}", e);
+ eprintln!("Ошибка чтения: {e}");
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
};
@@ -219,7 +221,7 @@ async fn serve_file(
if parent.is_empty() {
"/".to_string()
} else {
- format!("/{}", parent)
+ format!("/{parent}")
}
} else {
"/".to_string()
@@ -227,12 +229,11 @@ async fn serve_file(
let back_button_html = format!(
r#""#,
- back_link
+ "#
);
let html_content = markdown_to_html(&content, &state.syntax_set, &state.theme_set, &full_path);
@@ -240,7 +241,7 @@ async fn serve_file(
// Заполнение шаблона
let final_html = TEMPLATE_FILE
.replace("{{CONTENT}}", &html_content)
- .replace("{{SSE_URL}}", &format!("/events/{}", full_path))
+ .replace("{{SSE_URL}}", &format!("/events/{full_path}"))
.replace("{{BACK_BUTTON}}", &back_button_html);
Ok(Html(final_html))
@@ -253,7 +254,7 @@ async fn render_directory_index(
let mut entries = match fs::read_dir(dir_path).await {
Ok(list) => list,
Err(e) => {
- eprintln!("Ошибка чтения директории: {}", e);
+ eprintln!("Ошибка чтения директории: {e}");
return Err(StatusCode::FORBIDDEN);
}
};
@@ -291,24 +292,25 @@ async fn render_directory_index(
let mut list_html = String::from("");
if !request_path.is_empty() && request_path != "files" {
- let parent_path = request_path.rsplit_once('/').map(|(p, _)| p).unwrap_or("");
+ let parent_path = request_path.rsplit_once('/').map_or("", |(p, _)| p);
let parent_link = if parent_path.is_empty() {
"/".to_string()
} else {
- format!("/{}", parent_path)
+ format!("/{parent_path}")
};
- list_html.push_str(&format!(
+ let _ = write!(
+ list_html,
r#"-
- 📁 ..
-
"#,
- parent_link
- ));
+ 📁 ..
+ "#
+ );
}
for (name, link, is_dir) in files {
let icon = if is_dir { "📁" } else { "📄" };
- list_html.push_str(&format!(
+ let _ = write!(
+ list_html,
r#"-
{}
@@ -318,7 +320,7 @@ async fn render_directory_index(
link.trim_start_matches('/'),
icon,
name
- ));
+ );
}
list_html.push_str("
");
@@ -355,7 +357,7 @@ async fn run_file_watcher(state: AppState) {
let watch_path = PathBuf::from("./notes");
if let Err(e) = watcher.watch(&watch_path, RecursiveMode::Recursive) {
- eprintln!("Ошибка настройки watcher: {}", e);
+ eprintln!("Ошибка настройки watcher: {e}");
return;
}
@@ -406,9 +408,8 @@ fn markdown_to_html(markdown: &str, ss: &SyntaxSet, ts: &ThemeSet, _file_path: &
Mermaid Diagram
- {}
- "#,
- escaped_code
+ {escaped_code}
+ "#
);
processed_events.push(Event::Html(mermaid_html.into()));
} else {
@@ -420,7 +421,7 @@ fn markdown_to_html(markdown: &str, ss: &SyntaxSet, ts: &ThemeSet, _file_path: &
let mut h = HighlightLines::new(syntax, theme);
let mut result_html = String::new();
for line in current_code.lines() {
- let line_with_newline = format!("{}\n", line);
+ let line_with_newline = format!("{line}\n");
match h.highlight_line(&line_with_newline, ss) {
Ok(regions) => {
let html_line = styled_line_to_highlighted_html(
@@ -431,7 +432,7 @@ fn markdown_to_html(markdown: &str, ss: &SyntaxSet, ts: &ThemeSet, _file_path: &
result_html.push_str(&html_line);
}
Err(_) => {
- result_html.push_str(&escape_html(&line_with_newline))
+ result_html.push_str(&escape_html(&line_with_newline));
}
}
}
@@ -446,12 +447,11 @@ fn markdown_to_html(markdown: &str, ss: &SyntaxSet, ts: &ThemeSet, _file_path: &
let code_container = format!(
r#""#,
- lang_escaped, highlighted_html
+ {highlighted_html}
+ "#
);
processed_events.push(Event::Html(code_container.into()));
}