diff --git a/.llm/analysis.md b/.llm/analysis.md new file mode 100644 index 0000000..4d53391 --- /dev/null +++ b/.llm/analysis.md @@ -0,0 +1,268 @@ +# Analiza repozytorium: bin (Pastebin) + +> Data analizy: 2026-04-21 + +--- + +## 1. Cel projektu + +**Bin** to minimalistyczny, samodzielny serwis pastebin akceptujący zarówno tekst, jak i pliki binarne (obrazy, PDF-y itp.). Filozofia projektu opiera się na prostocie, łatwości wdrożenia i minimalizmie. W odróżnieniu od tradycyjnych pastebinów **nie wymaga bazy danych** — wszystkie pasty przechowywane są w płaskim systemie plików. Projekt zawiera klienty: interfejs webowy, CLI i integrację z Vimem. + +**Live demo:** https://basedbin.fly.dev +**Docker:** `wantguns/bin` (multi-arch: amd64 + arm64) + +--- + +## 2. Stack technologiczny + +| Warstwa | Technologia | +|---------|-------------| +| Język | Rust (Edition 2021) | +| Framework web | Rocket 0.5.0-rc.1 (async) | +| Szablony HTML | Tera (via rocket_dyn_templates) | +| Kolorowanie składni | Syntect 4.6.0 + motyw Ayu Dark | +| Frontend | Vanilla JavaScript, HTML, CSS (brak frameworków) | +| Detekcja MIME | tree_magic 0.2.3 | +| CLI args | clap 3.0.9 | +| Kryptografia | sha256 (ETag) | +| Obsadzanie zasobów | rust-embed 6.3.0 | +| Konteneryzacja | Docker (obraz scratch) | +| Deployment | Fly.io | + +--- + +## 3. Struktura katalogów + +``` +bin/ +├── src/ # Kod źródłowy Rust +│ ├── main.rs # Punkt wejścia, setup serwera, parsowanie CLI +│ ├── routes/ # Handlery endpointów HTTP +│ │ ├── mod.rs +│ │ ├── index.rs # GET / – strona główna +│ │ ├── upload.rs # POST / – upload pliku binarnego +│ │ ├── submit.rs # POST /submit – formularz tekstowy +│ │ ├── retrieve.rs # GET / – surowe pobranie pasty +│ │ ├── pretty_retrieve.rs # GET /p/ – wyświetlanie z podświetlaniem +│ │ └── static_files.rs # GET /static/ – zasoby statyczne +│ └── models/ +│ ├── mod.rs +│ ├── paste_id.rs # Generowanie i walidacja ID pasty +│ ├── pretty_syntax.rs # Parsowanie rozszerzenia z URL +│ ├── pretty.rs # Logika podświetlania składni +│ └── response_wrapper.rs # Abstrakcja odpowiedzi HTTP +│ +├── templates/ # Szablony Tera +│ ├── base.html.tera +│ ├── index.html.tera +│ └── pretty.html.tera +│ +├── static/ # Zasoby osadzone w binarce +│ ├── css/ +│ ├── js/ +│ ├── fonts/ # Iosevka (ttf + woff2) +│ └── media/ # Favicony +│ +├── resources/ # Zasoby binarne (syntaksy, motyw) +├── contrib/cli/client # Skrypt bash CLI +├── Cargo.toml # Manifest projektu +├── build.rs # Wstrzykiwanie git hash do binarki +├── Dockerfile # Wielostopniowy build +├── docker-compose.yml +└── fly.toml # Konfiguracja Fly.io +``` + +--- + +## 4. Endpointy API + +| Metoda | Ścieżka | Opis | +|--------|---------|------| +| GET | `/` | Strona główna z formularzem | +| GET | `/static/` | Zasoby statyczne (CSS, JS, czcionki) | +| POST | `/` | Upload pliku binarnego → zwraca ID | +| POST | `/submit` | Formularz tekstowy → redirect do `/p/.` | +| GET | `/` | Surowa treść pasty | +| GET | `/.` | Surowa treść z rozszerzeniem (rank=1) | +| GET | `/p/` | Pasta z podświetlaniem składni (HTML) | +| GET | `/p/.` | Pasta z wymuszonym językiem (rank=1) | + +**Priorytet routingu:** trasy z rozszerzeniem (`rank=1`) są dopasowywane przed trasami generycznymi (`rank=2`). + +--- + +## 5. Modele danych + +### PasteId +```rust +pub struct PasteId<'a>(Cow<'a, str>) +``` +- Generuje losowe 6-znakowe ID alfanumeryczne (36^6 ≈ 2,1 mld kombinacji) +- Implementuje `FromParam` dla automatycznej walidacji URL w Rocket + +### PasteIdSyntax +```rust +pub struct PasteIdSyntax<'a> { syn_id: Cow<'a, str> } +``` +- Parsuje URL typu `/p/abc123.cpp` na nazwę pliku i rozszerzenie +- `get_fname()` → `"abc123"`, `get_ext()` → `"cpp"` + +### ResponseWrapper +```rust +enum ResponseWrapper { + MetaInterfaceResponse(R), + PrettyPasteContentResponse(R, SystemTime), + RawPasteContentResponse(R, SystemTime), + Redirect(Box), + NotFound(String), + ServerError(String), +} +``` +Centralnie zarządza nagłówkami HTTP: +- `Server: bin v. ()` +- `ETag`, `Last-Modified`, `Cache-Control` + +--- + +## 6. Zależności (Cargo.toml) + +| Crate | Wersja | Zastosowanie | +|-------|--------|--------------| +| `rand` | 0.8.4 | Generowanie ID | +| `rocket` | 0.5.0-rc.1 | Framework web | +| `tree_magic` | 0.2.3 | Detekcja MIME | +| `syntect` | 4.6.0 | Podświetlanie składni | +| `rust-embed` | 6.3.0 | Osadzanie zasobów | +| `clap` | 3.0.9 | Parsowanie CLI | +| `once_cell` | 1 | Lazy static | +| `sha256` | 1 | ETag | +| `time` | 0.3 | Formatowanie czasu | +| `rocket_dyn_templates` | 0.1.0-rc.1 | Szablony Tera | + +--- + +## 7. System budowania + +### build.rs +Przechwytuje hash commita git i wstrzykuje go jako stałą czasu kompilacji (`GIT_HASH`). + +### .cargo/config.toml +- Kompilacja statyczna: `-C target-feature=+crt-static` +- Domyślny target: `x86_64-unknown-linux-gnu` +- Cross-kompilacja ARM64: `aarch64-linux-gnu-gcc` + +### Docker (wielostopniowy) +1. **Builder:** obraz Rust → `cargo build --release` +2. **Runner:** obraz `scratch` (pusty) + tylko binarka +3. Rezultat: minimalistyczny obraz (~20-30 MB) + +--- + +## 8. Konfiguracja serwera + +### Argumenty CLI + +| Flag | Domyślnie | Opis | +|------|-----------|------| +| `-a` | `127.0.0.1` | Adres nasłuchu | +| `-p` | `6162` | Port | +| `-u` | `./upload` | Katalog przechowywania plików | +| `-b` | `100 MiB` | Limit rozmiaru uploadu binarnego | +| `-c` | off | Pokaż opis klienta CLI na stronie głównej | + +### Zmienne środowiskowe (prefiks `BIN_`) +```bash +BIN_PORT=6163 +BIN_ADDRESS=0.0.0.0 +BIN_LIMITS={form="16 MiB"} +BIN_WORKERS=8 +BIN_IDENT=false +``` + +--- + +## 9. Architektura i wzorce projektowe + +1. **Embedded Resources** — wszystkie zasoby (CSS, JS, czcionki, definicje syntaksy) skompilowane w binarce (`rust-embed`). Zero zależności zewnętrznych. + +2. **Response Wrapper** — generyczny wrapper abstrakcji odpowiedzi z centralizowaną logiką nagłówków HTTP. + +3. **Type-Safe URL Params** — `PasteId` i `PasteIdSyntax` implementują trait `FromParam` — Rocket automatycznie waliduje parametry URL. + +4. **Lazy Static** — `BINARY_ETAG` obliczany raz przy starcie (SHA256 wersji) via `once_cell::sync::Lazy`. + +5. **Build-Time Version Injection** — hash git osadzony w czasie kompilacji, widoczny w nagłówku `Server`. + +6. **Flat Filesystem Storage** — brak bazy danych; pasty jako pliki w katalogu `./upload`. + +--- + +## 10. Frontend (JavaScript) + +### index.js (~150 linii) +- Drag-and-drop upload plików +- Wklejanie obrazów ze schowka (`paste` event) +- Tab jako 4 spacje (nie nawigacja formularza) +- Ctrl+Enter → submit +- Dynamiczne pokazywanie/ukrywanie UI +- Fork przez localStorage + +### pretty.js +- Przełącznik zawijania: 3 stany (brak → auto → 80 znaków) +- Fork: kopiuje treść do localStorage, przekierowuje na główną +- Raw: przełącza `/p/` → `/` +- New: przejście do strony głównej + +--- + +## 11. Strategia cachowania + +| Typ odpowiedzi | Cache-Control | +|----------------|---------------| +| Pasta pretty | `max-age=604800, stale-while-revalidate=86400` | +| Pasta raw | `max-age=604800, immutable` | +| Meta/Statyczne | ETag (SHA256 wersji) → `304 Not Modified` | + +--- + +## 12. Statystyki kodu + +| Metryka | Wartość | +|---------|---------| +| Pliki źródłowe Rust | 13 | +| Linie kodu Rust | ~600 | +| Szablony HTML | 3 | +| Pliki JavaScript | 2 | +| Arkusze CSS | 2 | +| Obsługiwane języki (syntaksy) | 100+ | +| Endpointy API | 7 | +| Typy odpowiedzi HTTP | 6 | + +--- + +## 13. Algorytmy kluczowe + +### Generowanie ID +``` +1. rand::thread_rng() → thread-safe RNG +2. Alphanumeric distribution (a-z, A-Z, 0-9) +3. Pobierz 6 próbek → String +4. Opakuj w Cow::Owned +``` + +### Detekcja MIME (upload binarny) +``` +1. Wczytaj bajty pliku +2. tree_magic::from_filepath() → MIME +3. MIME zawiera "text" → /p/ (kolorowanie) +4. Inaczej → / (surowe pobranie) +``` + +### Renderowanie składni +``` +1. Parsuj URL /p/abc123.cpp +2. Wyodrębnij rozszerzenie ("cpp") +3. Znajdź definicję syntaxu w syntect +4. Fallback → plain_text +5. Renderuj HTML z motywem Ayu Dark +``` diff --git a/Cargo.lock b/Cargo.lock index bb3e1a2..ec195eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler" @@ -14,7 +14,7 @@ version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "memchr 2.4.1", + "memchr 2.8.0", ] [[package]] @@ -102,6 +102,7 @@ version = "2.2.1" dependencies = [ "clap", "once_cell", + "pulldown-cmark", "rand", "rocket", "rocket_dyn_templates", @@ -133,6 +134,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + [[package]] name = "block-buffer" version = "0.7.3" @@ -169,7 +176,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "memchr 2.4.1", + "memchr 2.8.0", ] [[package]] @@ -255,7 +262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "indexmap", "lazy_static", @@ -284,7 +291,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -364,7 +371,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -481,7 +488,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fsevent-sys", ] @@ -500,7 +507,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fuchsia-zircon-sys", ] @@ -593,7 +600,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr 2.4.1", + "memchr 2.8.0", "pin-project-lite", "pin-utils", "slab", @@ -631,6 +638,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.2.4" @@ -667,7 +683,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -792,7 +808,7 @@ dependencies = [ "globset", "lazy_static", "log", - "memchr 2.4.1", + "memchr 2.8.0", "regex", "same-file", "thread_local", @@ -823,7 +839,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -978,9 +994,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mime" @@ -1075,7 +1091,7 @@ dependencies = [ "http", "httparse", "log", - "memchr 2.4.1", + "memchr 2.8.0", "mime", "spin", "tokio", @@ -1118,7 +1134,7 @@ version = "4.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" dependencies = [ - "bitflags", + "bitflags 1.3.2", "filetime", "fsevent", "fsevent-sys", @@ -1189,7 +1205,7 @@ version = "6.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225" dependencies = [ - "bitflags", + "bitflags 1.3.2", "lazy_static", "libc", "onig_sys", @@ -1223,7 +1239,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" dependencies = [ - "memchr 2.4.1", + "memchr 2.8.0", ] [[package]] @@ -1495,6 +1511,18 @@ dependencies = [ "yansi", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.11.1", + "getopts", + "memchr 2.8.0", + "unicase", +] + [[package]] name = "quote" version = "1.0.15" @@ -1556,7 +1584,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1586,7 +1614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", - "memchr 2.4.1", + "memchr 2.8.0", "regex-syntax", ] @@ -1631,7 +1659,7 @@ dependencies = [ "futures", "indexmap", "log", - "memchr 2.4.1", + "memchr 2.8.0", "multer", "num_cpus", "parking_lot 0.11.2", @@ -1695,7 +1723,7 @@ dependencies = [ "hyper", "indexmap", "log", - "memchr 2.4.1", + "memchr 2.8.0", "mime", "parking_lot 0.11.2", "pear", @@ -1956,7 +1984,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" dependencies = [ - "memchr 2.4.1", + "memchr 2.8.0", ] [[package]] @@ -2050,7 +2078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b20815bbe80ee0be06e6957450a841185fcf690fe0178f14d77a05ce2caa031" dependencies = [ "bincode", - "bitflags", + "bitflags 1.3.2", "flate2", "fnv", "lazy_static", @@ -2182,7 +2210,7 @@ checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" dependencies = [ "bytes", "libc", - "memchr 2.4.1", + "memchr 2.8.0", "mio 0.7.14", "num_cpus", "once_cell", @@ -2405,6 +2433,18 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 23212fd..92b5794 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ clap = { version = "3.0.9", features = ["derive", "env"] } once_cell = "1" sha256 = "1" time = { version = "0.3", features = ["formatting"] } +pulldown-cmark = "0.9" [dependencies.rocket_dyn_templates] version = "0.1.0-rc.1" diff --git a/src/main.rs b/src/main.rs index f4b856e..aaa5bbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ fn setup_tera_engine(tera: &mut Tera) { let base_html = EmbeddedTemplates::get("base.html.tera").unwrap(); let index_html = EmbeddedTemplates::get("index.html.tera").unwrap(); let pretty_html = EmbeddedTemplates::get("pretty.html.tera").unwrap(); + let markdown_html = EmbeddedTemplates::get("markdown.html.tera").unwrap(); // and shove them in the tera instance tera.add_raw_templates(vec![ @@ -44,6 +45,10 @@ fn setup_tera_engine(tera: &mut Tera) { "pretty.html", std::str::from_utf8(&pretty_html.data).unwrap(), ), + ( + "markdown.html", + std::str::from_utf8(&markdown_html.data).unwrap(), + ), ]) .expect("Could not add raw templates to the tera instance"); } @@ -108,7 +113,8 @@ fn rocket() -> _ { routes::retrieve::retrieve, routes::retrieve::retrieve_ext, routes::pretty_retrieve::pretty_retrieve, - routes::pretty_retrieve::pretty_retrieve_ext + routes::pretty_retrieve::pretty_retrieve_ext, + routes::markdown_retrieve::markdown_retrieve ], ) .attach(shield) diff --git a/src/models/markdown.rs b/src/models/markdown.rs new file mode 100644 index 0000000..9be76fa --- /dev/null +++ b/src/models/markdown.rs @@ -0,0 +1,110 @@ +use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; +use std::fs; +use std::path::Path; +use syntect::highlighting::{Theme, ThemeSet}; +use syntect::html::highlighted_html_for_string; +use syntect::parsing::SyntaxSet; + +static SYNTAXES: &[u8] = + include_bytes!("../../resources/syntaxes/syntaxes.bin"); +static AYU_DARK: &[u8] = + include_bytes!("../../resources/themes/ayu_dark.tmTheme"); + +pub const THEMES: &[(&str, &str)] = &[ + ("ayu-dark", "Ayu Dark"), + ("base16-ocean-dark", "Base16 Ocean Dark"), + ("base16-eighties", "Base16 Eighties"), + ("base16-mocha", "Base16 Mocha"), + ("base16-ocean-light", "Base16 Ocean Light"), + ("github", "GitHub"), + ("solarized-dark", "Solarized Dark"), + ("solarized-light", "Solarized Light"), +]; + +fn load_theme(name: &str) -> Theme { + match name { + "ayu-dark" | "" => { + let mut cursor = std::io::Cursor::new(AYU_DARK); + ThemeSet::load_from_reader(&mut cursor).unwrap() + } + other => { + let key = match other { + "github" => "InspiredGitHub", + "solarized-dark" => "Solarized (dark)", + "solarized-light" => "Solarized (light)", + "base16-ocean-dark" => "base16-ocean.dark", + "base16-eighties" => "base16-eighties.dark", + "base16-mocha" => "base16-mocha.dark", + "base16-ocean-light" => "base16-ocean.light", + _ => "base16-ocean.dark", + }; + let mut ts = ThemeSet::load_defaults(); + ts.themes.remove(key).unwrap_or_else(|| { + let mut cursor = std::io::Cursor::new(AYU_DARK); + ThemeSet::load_from_reader(&mut cursor).unwrap() + }) + } + } +} + +pub fn get_markdown_body(path: &Path, theme_name: &str) -> std::io::Result { + let content = fs::read_to_string(path)?; + + let ss: SyntaxSet = syntect::dumps::from_binary(SYNTAXES); + let theme = load_theme(theme_name); + + let options = Options::ENABLE_TABLES + | Options::ENABLE_FOOTNOTES + | Options::ENABLE_STRIKETHROUGH + | Options::ENABLE_TASKLISTS; + + let parser = Parser::new_ext(&content, options); + + let mut html_output = String::new(); + let mut in_code_block = false; + let mut code_lang = String::new(); + let mut code_content = String::new(); + + for event in parser { + match event { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref lang))) => { + in_code_block = true; + code_lang = lang.to_string(); + code_content.clear(); + } + Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { + in_code_block = true; + code_lang.clear(); + code_content.clear(); + } + Event::End(Tag::CodeBlock(_)) => { + in_code_block = false; + let syntax = if code_lang.is_empty() { + ss.find_syntax_plain_text() + } else { + ss.find_syntax_by_token(&code_lang) + .unwrap_or_else(|| ss.find_syntax_plain_text()) + }; + let highlighted = highlighted_html_for_string( + &code_content, + &ss, + syntax, + &theme, + ); + html_output.push_str(&highlighted); + code_content.clear(); + } + Event::Text(ref text) if in_code_block => { + code_content.push_str(text); + } + other => { + pulldown_cmark::html::push_html( + &mut html_output, + std::iter::once(other), + ); + } + } + } + + Ok(html_output) +} diff --git a/src/models/mod.rs b/src/models/mod.rs index 20dae4b..30effb3 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,3 +1,4 @@ +pub mod markdown; pub mod paste_id; pub mod pretty; pub mod pretty_syntax; diff --git a/src/routes/markdown_retrieve.rs b/src/routes/markdown_retrieve.rs new file mode 100644 index 0000000..7722adb --- /dev/null +++ b/src/routes/markdown_retrieve.rs @@ -0,0 +1,63 @@ +use rocket_dyn_templates::Template; +use std::collections::HashMap; +use std::fs; +use std::io::ErrorKind::NotFound; +use std::path::Path; + +use crate::get_upload_dir; +use crate::models::markdown::{get_markdown_body, THEMES}; +use crate::models::paste_id::PasteId; +use crate::models::response_wrapper::ResponseWrapper; + +#[get("/m/?")] +pub async fn markdown_retrieve( + id: PasteId<'_>, + theme: Option<&str>, +) -> ResponseWrapper