Compare commits

...

10 commits

28 changed files with 1401 additions and 614 deletions

573
Cargo.lock generated
View file

@ -38,6 +38,55 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -57,18 +106,45 @@ dependencies = [
"unscanny",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "camino"
version = "1.1.6"
@ -98,7 +174,7 @@ dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
"windows-targets 0.52.4",
]
[[package]]
@ -138,12 +214,58 @@ dependencies = [
"serde",
]
[[package]]
name = "clap"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim 0.11.1",
]
[[package]]
name = "clap_derive"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "clap_lex"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "codemap"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24"
[[package]]
name = "colorchoice"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "copy_dir"
version = "0.1.3"
@ -159,12 +281,46 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "darling"
version = "0.14.4"
@ -185,7 +341,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim",
"strsim 0.10.0",
"syn 1.0.109",
]
@ -200,6 +356,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "data-encoding"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "derive_builder"
version = "0.12.0"
@ -231,6 +393,16 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "displaydoc"
version = "0.2.4"
@ -263,6 +435,18 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "filetime"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"windows-sys 0.52.0",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -278,6 +462,25 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getopts"
version = "0.2.21"
@ -390,6 +593,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "html-escape"
version = "0.2.13"
@ -399,6 +608,23 @@ dependencies = [
"utf8-width",
]
[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "httparse"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "hypertext"
version = "0.5.0"
@ -475,6 +701,32 @@ dependencies = [
"serde",
]
[[package]]
name = "inotify"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
dependencies = [
"bitflags 1.3.2",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "itertools"
version = "0.10.5"
@ -512,6 +764,26 @@ dependencies = [
"thiserror",
]
[[package]]
name = "kqueue"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]]
name = "lasso"
version = "0.7.2"
@ -562,13 +834,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "npezza93-tree-sitter-haskell"
version = "0.15.1"
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd44dfc09a37bafbed1c28622c662be9b8fb1aaaad0444688370eae11e3d54b0"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"cc",
"tree-sitter",
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "notify"
version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
"bitflags 2.5.0",
"crossbeam-channel",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"log",
"mio",
"walkdir",
"windows-sys 0.48.0",
]
[[package]]
name = "notify-debouncer-mini"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43"
dependencies = [
"crossbeam-channel",
"log",
"notify",
]
[[package]]
@ -701,7 +1005,7 @@ name = "pulldown-cmark"
version = "0.10.0"
source = "git+https://github.com/pulldown-cmark/pulldown-cmark.git?branch=branch_0.11#2540d4095d5f94fd972c93b927e9bec83b0c5079"
dependencies = [
"bitflags",
"bitflags 2.5.0",
"getopts",
"memchr",
"pulldown-cmark-escape",
@ -772,6 +1076,15 @@ dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.10.4"
@ -880,6 +1193,17 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "siphasher"
version = "0.3.11"
@ -892,6 +1216,7 @@ version = "0.1.0"
dependencies = [
"camino",
"chrono",
"clap",
"emojis",
"glob",
"grass",
@ -899,19 +1224,27 @@ dependencies = [
"hayagriva",
"hypertext",
"katex",
"npezza93-tree-sitter-haskell",
"notify",
"notify-debouncer-mini",
"once_cell",
"pulldown-cmark",
"regex",
"serde",
"tree-sitter",
"tree-sitter-css",
"tree-sitter-haskell",
"tree-sitter-highlight",
"tree-sitter-html",
"tree-sitter-javascript",
"tree-sitter-md",
"tree-sitter-python",
"tree-sitter-query",
"tree-sitter-regex",
"tree-sitter-rust",
"tree-sitter-scss",
"tree-sitter-toml-ng",
"tree-sitter-typescript",
"tungstenite",
]
[[package]]
@ -920,6 +1253,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.26.2"
@ -935,7 +1274,7 @@ version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
dependencies = [
"heck",
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
@ -978,18 +1317,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
dependencies = [
"proc-macro2",
"quote",
@ -1022,19 +1361,39 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tree-sitter"
version = "0.22.5"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "688200d842c76dd88f9a7719ecb0483f79f5a766fb1c100756d5d8a059abc71b"
checksum = "df7cc499ceadd4dcdf7ec6d4cbc34ece92c3fa07821e287aedecd4416c516dca"
dependencies = [
"cc",
"regex",
]
[[package]]
name = "tree-sitter-highlight"
version = "0.22.5"
name = "tree-sitter-css"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9442daef896b114ed618a5e11c9ba9663796ab3600e544d57f2dc980fa0d2d78"
checksum = "e2f806f96136762b0121f5fdd7172a3dcd8f42d37a2f23ed7f11b35895e20eb4"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-haskell"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef25a7e6c73cc1cbe0c0b7dbd5406e7b3485b370bd61c5d8d852ae0781f9bf9a"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-highlight"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaca0fe34fa96eec6aaa8e63308dbe1bafe65a6317487c287f93938959b21907"
dependencies = [
"lazy_static",
"regex",
@ -1043,10 +1402,20 @@ dependencies = [
]
[[package]]
name = "tree-sitter-javascript"
version = "0.21.0"
name = "tree-sitter-html"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26eca1925fd9518f9439ea122e3f3395abb3fcfc4b0841ef94eeef934871ec59"
checksum = "95b3492b08a786bf5cc79feb0ef2ff3b115d5174364e0ddfd7860e0b9b088b53"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-javascript"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "080880908cb6e8d03cb9ceaeecec9a3d3a2f4e122e74642509bbb22aaefd991b"
dependencies = [
"cc",
"tree-sitter",
@ -1075,7 +1444,17 @@ dependencies = [
[[package]]
name = "tree-sitter-query"
version = "0.2.1"
source = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?rev=608c01187fb9f525a1e4cf585bb63d73dea280b7#608c01187fb9f525a1e4cf585bb63d73dea280b7"
source = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?rev=87b1a3d#87b1a3dc6c5a76c5cedcdfc60efe75805468cb90"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-regex"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ff1286fe9651b2797484839ffa37aa76c8618d4ccb6836d7e31765dfd60c0d5"
dependencies = [
"cc",
"tree-sitter",
@ -1101,6 +1480,51 @@ dependencies = [
"tree-sitter",
]
[[package]]
name = "tree-sitter-toml-ng"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "695d20cd83acf16c02c773f03e76d7b43b19883d4e2ce3652a8f06b5e0da7455"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-typescript"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f07523e51e3b88529360a89038c0cca7ee877db40a40141514eece8b4cddcbb4"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tungstenite"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http",
"httparse",
"log",
"rand",
"sha1",
"thiserror",
"url",
"utf-8",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unic-langid"
version = "0.9.4"
@ -1186,12 +1610,24 @@ dependencies = [
"serde",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
@ -1305,7 +1741,40 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
"windows-targets 0.52.4",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@ -1314,51 +1783,93 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
camino = "1.1.6"
chrono = "0.4.35"
clap = { version = "4.5.4", features = ["derive"] }
emojis = "0.6.1"
glob = "0.3.1"
grass = { version = "0.13.2", default-features = false, features = ["random"] }
@ -17,6 +18,11 @@ once_cell = "1.19.0"
regex = "1.10.4"
serde = { version = "1.0.197", features = ["derive"] }
# Watch
notify = "6.1.1"
notify-debouncer-mini = "0.4.1"
tungstenite = "0.21.0"
# Markdown
pulldown-cmark = { git = "https://github.com/pulldown-cmark/pulldown-cmark.git", branch = "branch_0.11" }
@ -26,15 +32,15 @@ tree-sitter-highlight = "0.22"
# Treesitter languages
# tree-sitter-astro = { git = "https://github.com/virchau13/tree-sitter-astro.git", rev = "e924787e12e8a03194f36a113290ac11d6dc10f3" }
# tree-sitter-css = "0.20.0"
# tree-sitter-haskell = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "1da347c88599faad7964e63facead5d163ac7dba" }
npezza93-tree-sitter-haskell = "0.15.1"
tree-sitter-css = "0.21"
tree-sitter-haskell = "0.21"
tree-sitter-html = "0.20.3"
tree-sitter-javascript = "0.21"
tree-sitter-md = "0.2"
tree-sitter-python = "0.21"
tree-sitter-query = { git = "https://github.com/tree-sitter-grammars/tree-sitter-query", rev = "608c01187fb9f525a1e4cf585bb63d73dea280b7" }
# tree-sitter-regex = "0.20.0"
tree-sitter-regex = "0.21"
tree-sitter-rust = "0.21"
tree-sitter-scss = "1"
# tree-sitter-toml = "0.20.0"
# tree-sitter-typescript = "0.20.5"
tree-sitter-query = { git = "https://github.com/tree-sitter-grammars/tree-sitter-query", rev = "87b1a3d" }
tree-sitter-toml-ng = "0.6"
tree-sitter-typescript = "0.21"

View file

@ -1,8 +1,11 @@
build:
cargo run
cargo run --release
deploy: build
rsync -Pavzq ./dist/ kamoshi:/var/www/kamoshi.org --delete
watch:
cargo run --release -- watch
serve:
python -m http.server -d ./dist
deploy: build
rsync -Pavzq ./dist/ kamoshi:/var/www/kamoshi.org --delete

View file

@ -11,22 +11,22 @@ date: 2023-12-17T12:47:29.753Z
あくる日、親に引かれている橇で乗っている嬉しそうな子供を見た。
あらゆる公園が白くなって、白すぎて見えた。
![白すぎる公園](@assets/posts/hisasiburi-no-toukou/IMG_20231204_105929.jpg)
![白すぎる公園](IMG_20231204_105929.jpg)
その時から雪が全部解けちゃった。
最近、ヴロツワフではクリスマスマーケットが始まっているので、見に行った。
そこでたくさんの人がいて、いろんな出店もあり、色々なものを買って楽しむことができた。
![眩しいクリスマスライト](@assets/posts/hisasiburi-no-toukou/IMG_20231209_182036.jpg)
![眩しいクリスマスライト](IMG_20231209_182036.jpg)
もっと進んでいくと、大きなレストランみたいなビルに出くわしたんだ。
あのビルでは、「グジャニエッツ」という飲み物を買って楽しむことができた。
![グジャニエッツのビル](@assets/posts/hisasiburi-no-toukou/IMG_20231209_183410.jpg)
![グジャニエッツのビル](IMG_20231209_183410.jpg)
グジャニエッツとは、ポーランドの伝統的な温かいスパイス入りの飲み物。
通常は赤ワインやオレンジ、シナモン、クローブが使われる。
クリスマスマーケットってとても素晴らしいイベントの一つだけど、値段が高く過ぎるからあんまり買い物しなかったwww
クリスマスマーケットってとても素晴らしいイベントの一つだけど、
値段が高く過ぎるからあんまり買い物しなかったwww

View file

@ -0,0 +1,78 @@
---
title: SSG that packs a punch
date: 2024-05-02T21:17:43Z
desc: >
Let's create a yet another SSG from scratch, because that's just
what this world needs!
---
Long story short, I decided to write my own static site generator in Rust. The
language choice is purely pragmatic and at first I considered using Haskell,
but alas the Rust ecosystem seems better suited for this task. Rust is not only
a very ergonomic and efficient language, but also has lots of high quality
packages to choose from.
## The why
I used many different SSGs made by other people, but over the years I realized
that they simply can't cut it for me. I used simple generators like Hugo, which
offer little to no support for JavaScript. Eventually I ended up using Astro,
which treats JavaScript as a first class citizen.
The thing I didn't like the most about Hugo, was that it used some strange,
clumsy templating language, which was quite annoying to use, but I enjoyed the
fact that nearly everything was built in, and the generation speed was fast.
When it comes to Astro, I enjoyed the fact that in templates you could write
TypeScript, as well the great flexibility with which you could arrange the
structure of the website. However, the JavaScript ecosystem is a mess, so using
that was not that pleasant overall.
Astro was closer to what I wanted, but not quite there.
With time, I realized that what I truly need is the flexibility of Astro,
coupled with a different language. Ideally a fun one like Haskell or Rust.
I started looking around and came across a couple of [blog
posts](https://arne.me/blog/write-your-own-ssg) detailing how people made the
move to their custom generator. This was the inspiration I needed.
I thought that even if it ends up quite bad in the end, at least I'll learn
*something*. And it would be a good chance to learn more Rust, so that's a win
right there. With Haskell it would be an ever bigger win, but hey, can't have
everything in life.
## The what
When trying to write a computer program it's a good idea to think about what it
should ideally be able to do. We should at least know the sketch of the
requirements before we start, so that we know if we are getting any closer to
the goal as we keep writing it.
When it comes to my generator I think I would like for it to have these
qualities:
- The generator must be *simple* and *extensible*
- HTML shouldn't be generated using some bespoke templating language, I should
have the full ecosystem at my disposal.
- Ideally I should not be limited to Markdown, I should be able to use
different file text formats as needed, e.g. Djot, AsciiDoc.
- Code snippets should be highlighted using Tree-sitter.
- Math should be pre-rendered via MathML without any client-side JavaScript.
- There should be a way to render different pages differently, some collections
of Markdown files should output different looking pages.
- I should be able to generate HTML pages that don't have any original source
files related to them, think dynamically generated lists of pages, tags.
With these requirements in mind I decided to go with Rust, because Rust has
lots of up-to-date parsers that can be used while building a generator. On top
of that I can use Tree-sitter without any need for complicated FFI or using
outdated libraries in other ecosystems.
When moving to a non-JavaScript backend for building SSG some issues related to
JavaScript inevitably start to crop up. There is some friction with using tools
like ESBuild, but I feel like the benefits far outweigh the challenges in the
end.
## The how

View file

@ -241,41 +241,3 @@ scala
### Rust
rust
## Bibliography
:::bibtex
@inproceedings{10.1145/1238844.1238856,
author = {Hudak, Paul and Hughes, John and Peyton Jones, Simon and Wadler, Philip},
title = {A History of Haskell: Being Lazy with Class},
year = {2007},
isbn = {9781595937667},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/1238844.1238856},
doi = {10.1145/1238844.1238856},
abstract = {This paper describes the history of Haskell, including its genesis and principles, technical contributions, implementations and tools, and applications and impact.},
booktitle = {Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages},
pages = {1211255},
location = {San Diego, California},
series = {HOPL III}
}
@online{youtube,
title = {Escape from the ivory tower: the Haskell journey},
date = {2017},
organization = {Youtube},
author = {Simon {Peyton Jones}},
url = {https://youtu.be/re96UgMk6GQ},
}
@book{skinner2023effective,
title = {Effective Haskell: Solving Real-World Problems with Strongly Typed Functional Programming},
author = {Skinner, R.},
isbn = {9781680509342},
series = {Pragmatic Bookshelf},
year = {2023},
publisher = {O'Reilly Media}
}
:::

View file

@ -0,0 +1,32 @@
@inproceedings{10.1145/1238844.1238856,
author = {Hudak, Paul and Hughes, John and Peyton Jones, Simon and Wadler, Philip},
title = {A History of Haskell: Being Lazy with Class},
year = {2007},
isbn = {9781595937667},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/1238844.1238856},
doi = {10.1145/1238844.1238856},
abstract = {This paper describes the history of Haskell, including its genesis and principles, technical contributions, implementations and tools, and applications and impact.},
booktitle = {Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages},
pages = {1211255},
location = {San Diego, California},
series = {HOPL III}
}
@online{youtube,
title = {Escape from the ivory tower: the Haskell journey},
date = {2017},
organization = {Youtube},
author = {Simon {Peyton Jones}},
url = {https://youtu.be/re96UgMk6GQ},
}
@book{skinner2023effective,
title = {Effective Haskell: Solving Real-World Problems with Strongly Typed Functional Programming},
author = {Skinner, R.},
isbn = {9781680509342},
series = {Pragmatic Bookshelf},
year = {2023},
publisher = {O'Reilly Media}
}

View file

@ -20,46 +20,3 @@ It's really powerful.
## Summary
It was a pretty fun and interesting adventure, difficult at times, but worth it over all. In hindsight, I regret not paying more attention to mathematics right from the start. If I were to start over I would probably focus more on that and the theory of computation. If you're only just starting out then please remember, writing code is not computer science :cat:
## Bibliography
:::bibtex
@book{gamma1994design,
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
author = {Gamma, E. and Helm, R. and Johnson, R. and Vlissides, J.},
isbn = {9780321700698},
lccn = {94034264},
series = {Addison-Wesley Professional Computing Series},
year = {1994},
publisher = {Pearson Education}
}
@book{chollet2021deep,
title = {Deep Learning with Python, Second Edition},
author = {Chollet, F.},
isbn = {9781617296864},
lccn = {2021425412},
year = {2021},
publisher = {Manning}
}
@article{10.1145/360303.360308,
author = {Tennent, R. D.},
title = {The Denotational Semantics of Programming Languages},
year = {1976},
issue_date = {Aug. 1976},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
volume = {19},
number = {8},
issn = {0001-0782},
url = {https://doi.org/10.1145/360303.360308},
doi = {10.1145/360303.360308},
journal = {Commun. ACM},
month = {aug},
pages = {437453},
numpages = {17},
keywords = {semantics, GEDANKEN, store, environment, LOOP, continuation, applicative, higher-order function, imperative, programming language, theory of computation, recursive definition}
}
:::

View file

@ -0,0 +1,37 @@
@book{gamma1994design,
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
author = {Gamma, E. and Helm, R. and Johnson, R. and Vlissides, J.},
isbn = {9780321700698},
lccn = {94034264},
series = {Addison-Wesley Professional Computing Series},
year = {1994},
publisher = {Pearson Education}
}
@book{chollet2021deep,
title = {Deep Learning with Python, Second Edition},
author = {Chollet, F.},
isbn = {9781617296864},
lccn = {2021425412},
year = {2021},
publisher = {Manning}
}
@article{10.1145/360303.360308,
author = {Tennent, R. D.},
title = {The Denotational Semantics of Programming Languages},
year = {1976},
issue_date = {Aug. 1976},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
volume = {19},
number = {8},
issn = {0001-0782},
url = {https://doi.org/10.1145/360303.360308},
doi = {10.1145/360303.360308},
journal = {Commun. ACM},
month = {aug},
pages = {437453},
numpages = {17},
keywords = {semantics, GEDANKEN, store, environment, LOOP, continuation, applicative, higher-order function, imperative, programming language, theory of computation, recursive definition}
}

View file

@ -0,0 +1,18 @@
---
title: 〜めが
---
め and が can be used as pejorative suffixes at the end of a noun.
An example for め is:
> [馬鹿]{ばか}め!
More can be read [here](https://japanese.stackexchange.com/questions/95851).
Similarly to め, が can be used as a suffix of insult:
> この[小娘]{こむすめ}が(っ)!
More can be read [here](https://japanese.stackexchange.com/questions/60514).
Finally, the two can be used together as in:
> あの…馬鹿者めが…

7
src/build.rs Normal file
View file

@ -0,0 +1,7 @@
use std::fs;
pub fn build_styles() {
let css = grass::from_path("styles/styles.scss", &grass::Options::default()).unwrap();
fs::write("dist/styles.css", css).unwrap();
}

View file

@ -1,54 +1,111 @@
use std::collections::HashSet;
use std::fs::{self, File};
use std::io::Write;
use camino::Utf8PathBuf;
use camino::{Utf8Path, Utf8PathBuf};
use glob::glob;
use hayagriva::Library;
use crate::html::Linkable;
use super::Sack;
/// Marks whether the item should be treated as a content page, converted into a standalone HTML
/// page, or as a bundled asset.
#[derive(Debug)]
pub enum SourceKind {
pub enum FileItemKind {
/// Convert to `index.html`
Index,
Asset,
/// Convert to a bundled asset
Bundle,
}
/// Metadata for a single item consumed by SSG.
#[derive(Debug)]
pub struct Source {
pub kind: SourceKind,
pub ext: String,
pub dirs: Utf8PathBuf,
pub struct FileItem {
/// Kind of an item
pub kind: FileItemKind,
/// Original source file location
pub path: Utf8PathBuf,
}
fn to_source(path: Utf8PathBuf, exts: &HashSet<&'static str>) -> Source {
let dir = path.parent().unwrap();
let ext = path.extension().unwrap();
if !exts.contains(ext) {
return Source {
kind: SourceKind::Asset,
ext: ext.to_owned(),
dirs: dir.to_owned(),
path,
};
/// Marks how the asset should be processed by the SSG
pub enum AssetKind {
/// Data renderable to HTML
Html(Box<dyn Fn(&Sack) -> String>),
/// Bibliographical data
Bibtex(Library),
/// Images
Image,
}
let dirs = match path.file_stem().unwrap() {
"index" => dir.to_owned(),
name => dir.join(name),
};
/// Asset renderable by the SSG
pub struct Asset {
/// Kind of a processed asset
pub kind: AssetKind,
/// File metadata
pub meta: FileItem,
}
Source {
kind: SourceKind::Index,
ext: ext.to_owned(),
dirs,
path,
/// Dynamically generated asset not related to any disk file.
pub struct Dynamic(pub Box<dyn Fn(&Sack) -> String>);
impl Dynamic {
pub fn new(call: impl Fn(&Sack) -> String + 'static) -> Self {
Self(Box::new(call))
}
}
pub enum OutputKind {
Real(Asset),
Fake(Dynamic),
}
impl From<Asset> for OutputKind {
fn from(value: Asset) -> Self {
OutputKind::Real(value)
}
}
impl From<Dynamic> for OutputKind {
fn from(value: Dynamic) -> Self {
OutputKind::Fake(value)
}
}
/// Renderable output
pub struct Output {
pub kind: OutputKind,
pub path: Utf8PathBuf,
/// Optional link to outputted page.
pub link: Option<Linkable>,
}
/// Variants used for filtering static assets.
pub enum PipelineItem {
/// Unclaimed file, unrecognized file extensions.
Skip(FileItem),
/// Data ready to be processed by SSG.
Take(Output),
}
impl From<FileItem> for PipelineItem {
fn from(value: FileItem) -> Self {
Self::Skip(value)
}
}
impl From<Output> for PipelineItem {
fn from(value: Output) -> Self {
Self::Take(value)
}
}
pub fn gather(pattern: &str, exts: &HashSet<&'static str>) -> Vec<Source> {
pub fn gather(pattern: &str, exts: &HashSet<&'static str>) -> Vec<PipelineItem> {
glob(pattern)
.unwrap()
.expect("Invalid glob pattern")
.filter_map(|path| {
let path = path.unwrap();
let path = Utf8PathBuf::from_path_buf(path).expect("Filename is not valid UTF8");
@ -58,5 +115,62 @@ pub fn gather(pattern: &str, exts: &HashSet<&'static str>) -> Vec<Source> {
false => Some(to_source(path, exts))
}
})
.map(Into::into)
.collect()
}
fn to_source(path: Utf8PathBuf, exts: &HashSet<&'static str>) -> FileItem {
let hit = path.extension().map_or(false, |ext| exts.contains(ext));
let kind = match hit {
true => FileItemKind::Index,
false => FileItemKind::Bundle,
};
FileItem {
kind,
path,
}
}
pub fn render_all(items: &[Output]) {
for item in items {
let file = match &item.kind {
OutputKind::Real(a) => Some(&a.meta.path),
OutputKind::Fake(_) => None,
};
render(item, &Sack::new(items, &item.path, file));
}
}
fn render(item: &Output, sack: &Sack) {
let o = Utf8Path::new("dist").join(&item.path);
fs::create_dir_all(o.parent().unwrap()).unwrap();
match item.kind {
OutputKind::Real(ref real) => {
let i = &real.meta.path;
match &real.kind {
AssetKind::Html(closure) => {
let mut file = File::create(&o).unwrap();
file.write_all(closure(sack).as_bytes()).unwrap();
println!("HTML: {} -> {}", i, o);
},
AssetKind::Bibtex(_) => { },
AssetKind::Image => {
fs::create_dir_all(o.parent().unwrap()).unwrap();
fs::copy(i, &o).unwrap();
println!("Image: {} -> {}", i, o);
},
};
},
OutputKind::Fake(Dynamic(ref closure)) => {
let mut file = File::create(&o).unwrap();
file.write_all(closure(sack).as_bytes()).unwrap();
println!("Virtual: -> {}", o);
},
}
}

View file

@ -1,19 +1,17 @@
mod load;
mod render;
mod sack;
use camino::Utf8PathBuf;
use hayagriva::Library;
use hypertext::Renderable;
pub use load::{gather, Source, SourceKind};
pub use render::{render, Asset, AssetKind, Virtual, Item};
pub use load::{gather, render_all, FileItem, FileItemKind, Asset, AssetKind, PipelineItem, Dynamic, Output};
pub use sack::{TreePage, Sack};
use crate::{html::Linkable, text::md::Outline};
/// Represents a piece of content that can be rendered into a page.
/// Represents a piece of content that can be rendered as a page.
pub trait Content {
fn transform<'f, 'm, 's, 'html, T>(
&'f self,

View file

@ -1,125 +0,0 @@
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::Write;
use camino::{Utf8Path, Utf8PathBuf};
use crate::html::Linkable;
use crate::Sack;
pub enum AssetKind {
Html(Box<dyn Fn(&Sack) -> String>),
Image,
Unknown,
Bib(hayagriva::Library),
}
impl Debug for AssetKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Html(ptr) => f.debug_tuple("Html").field(&format!("{:p}", *ptr)).finish(),
Self::Image => write!(f, "Image"),
Self::Unknown => write!(f, "Unknown"),
Self::Bib(bib) => f.debug_tuple("Bib").field(bib).finish(),
}
}
}
#[derive(Debug)]
pub struct Asset {
pub kind: AssetKind,
pub out: Utf8PathBuf,
pub link: Option<Linkable>,
pub meta: super::Source,
}
pub struct Virtual(pub Utf8PathBuf, pub Box<dyn Fn(&Sack) -> String>);
impl Virtual {
pub fn new<P, F>(path: P, call: F) -> Self
where
P: AsRef<Utf8Path>,
F: Fn(&Sack) -> String + 'static
{
Self(path.as_ref().into(), Box::new(call))
}
}
pub enum Item {
Real(Asset),
Fake(Virtual),
}
impl From<Asset> for Item {
fn from(value: Asset) -> Self {
Item::Real(value)
}
}
impl From<Virtual> for Item {
fn from(value: Virtual) -> Self {
Item::Fake(value)
}
}
pub fn render(items: &[Item]) {
let assets: Vec<&Asset> = items
.iter()
.filter_map(|item| match item {
Item::Real(a) => Some(a),
Item::Fake(_) => None,
})
.collect();
for item in items {
match item {
Item::Real(real) => render_real(real, &Sack::new(&assets, &real.out)),
Item::Fake(fake) => render_fake(fake, &Sack::new(&assets, &fake.0)),
}
}
}
fn render_real(item: &Asset, sack: &Sack) {
match &item.kind {
AssetKind::Html(render) => {
let i = &item.meta.path;
let o = Utf8Path::new("dist").join(&item.out);
fs::create_dir_all(o.parent().unwrap()).unwrap();
let mut file = File::create(&o).unwrap();
file.write_all(render(sack).as_bytes()).unwrap();
println!("HTML: {} -> {}", i, o);
},
AssetKind::Image => {
let i = &item.meta.path;
let o = Utf8Path::new("dist").join(&item.out);
fs::create_dir_all(o.parent().unwrap()).unwrap();
fs::copy(i, &o).unwrap();
println!("Image: {} -> {}", i, o);
},
AssetKind::Bib(_) => (),
AssetKind::Unknown => {
let i = &item.meta.path;
let o = Utf8Path::new("dist").join(&item.out);
fs::create_dir_all(o.parent().unwrap()).unwrap();
fs::copy(i, &o).unwrap();
println!("Unknown: {} -> {}", i, o);
},
}
}
fn render_fake(item: &Virtual, sack: &Sack) {
let Virtual(out, render) = item;
let o = Utf8Path::new("dist").join(out);
fs::create_dir_all(o.parent().unwrap()).unwrap();
let mut file = File::create(&o).unwrap();
file.write_all(render(sack).as_bytes()).unwrap();
println!("Virtual: -> {}", o);
}

View file

@ -1,11 +1,11 @@
use std::collections::HashMap;
use camino::Utf8PathBuf;
use camino::{Utf8Path, Utf8PathBuf};
use hayagriva::Library;
use crate::html::{Link, LinkDate, Linkable};
use super::{Asset, AssetKind};
use super::{load::{Output, OutputKind}, AssetKind};
#[derive(Debug)]
@ -34,23 +34,27 @@ impl TreePage {
}
/// This struct allows for querying the website hierarchy.
#[derive(Debug)]
/// This struct allows for querying the website hierarchy. Separate instance of this struct is
/// passed to each closure contained by some rendered assets.
pub struct Sack<'a> {
assets: &'a [&'a Asset],
/// Literally everything
hole: &'a [Output],
/// Current path for page
path: &'a Utf8PathBuf,
/// Original file location
file: Option<&'a Utf8PathBuf>,
}
impl<'a> Sack<'a> {
pub fn new(assets: &'a [&'a Asset], path: &'a Utf8PathBuf) -> Self {
Self { assets, path }
pub fn new(hole: &'a [Output], path: &'a Utf8PathBuf, file: Option<&'a Utf8PathBuf>) -> Self {
Self { hole, path, file }
}
pub fn get_links(&self, path: &str) -> Vec<LinkDate> {
let pattern = glob::Pattern::new(path).unwrap();
self.assets.iter()
.filter(|f| pattern.matches_path(f.out.as_ref()))
.filter_map(|f| match &f.link {
let pattern = glob::Pattern::new(path).expect("Bad glob pattern");
self.hole.iter()
.filter(|item| pattern.matches_path(item.path.as_ref()))
.filter_map(|item| match &item.link {
Some(Linkable::Date(link)) => Some(link.clone()),
_ => None,
})
@ -58,10 +62,10 @@ impl<'a> Sack<'a> {
}
pub fn get_tree(&self, path: &str) -> TreePage {
let glob = glob::Pattern::new(path).unwrap();
let list = self.assets.iter()
.filter(|f| glob.matches_path(f.out.as_ref()))
.filter_map(|f| match &f.link {
let glob = glob::Pattern::new(path).expect("Bad glob pattern");
let list = self.hole.iter()
.filter(|item| glob.matches_path(item.path.as_ref()))
.filter_map(|item| match &item.link {
Some(Linkable::Link(link)) => Some(link.clone()),
_ => None,
});
@ -76,18 +80,32 @@ impl<'a> Sack<'a> {
pub fn get_library(&self) -> Option<&Library> {
let glob = format!("{}/*.bib", self.path.parent()?);
let glob = glob::Pattern::new(&glob).unwrap();
let glob = glob::Pattern::new(&glob).expect("Bad glob pattern");
let opts = glob::MatchOptions {
case_sensitive: true,
require_literal_separator: true,
require_literal_leading_dot: false,
};
self.assets.iter()
.filter(|asset| glob.matches_path_with(asset.out.as_ref(), opts))
self.hole.iter()
.filter(|item| glob.matches_path_with(item.path.as_ref(), opts))
.filter_map(|asset| match asset.kind {
OutputKind::Real(ref real) => Some(real),
_ => None,
})
.find_map(|asset| match asset.kind {
AssetKind::Bib(ref lib) => Some(lib),
_ => None
AssetKind::Bibtex(ref lib) => Some(lib),
_ => None,
})
}
/// Get the path for output
pub fn get_path(&self) -> &'a Utf8Path {
self.path.as_path()
}
/// Get the path for original file location
pub fn get_file(&self) -> Option<&'a Utf8Path> {
self.file.map(Utf8PathBuf::as_ref)
}
}

View file

@ -1,8 +1,28 @@
use camino::Utf8Path;
use hypertext::{html_elements, maud, maud_move, GlobalAttributes, Raw, Renderable};
use crate::REPO;
const JS_RELOAD: &str = r#"
const socket = new WebSocket("ws://localhost:1337");
socket.addEventListener("message", (event) => {
console.log(event);
window.location.reload();
});
"#;
const JS_IMPORTS: &str = r#"
{
"imports": {
"splash": "/js/splash.js",
"reveal": "/js/reveal.js",
"photos": "/js/photos.js",
}
}
"#;
pub fn head(title: &str) -> impl Renderable + '_ {
let title = format!("{} | kamoshi.org", title);
@ -13,16 +33,6 @@ pub fn head(title: &str) -> impl Renderable + '_ {
(title)
}
script type="importmap" {(Raw(r#"
{
"imports": {
"splash": "/js/splash.js",
"reveal": "/js/reveal.js",
"photos": "/js/photos.js"
}
}
"#))}
// link rel="sitemap" href="/sitemap.xml";
link rel="stylesheet" href="/styles.css";
@ -33,6 +43,10 @@ pub fn head(title: &str) -> impl Renderable + '_ {
link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png";
link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png";
link rel="icon" href="/favicon.ico" sizes="any";
script type="importmap" {(Raw(JS_IMPORTS))}
script { (Raw(JS_RELOAD)) }
)
}
@ -81,11 +95,15 @@ pub fn navbar() -> impl Renderable {
)
}
pub fn footer() -> impl Renderable {
pub fn footer(path: Option<&Utf8Path>) -> impl Renderable {
let copy = format!("Copyright &copy; {} Maciej Jur", &REPO.year);
let mail = "maciej@kamoshi.org";
let href = format!("mailto:{}", mail);
let repo = format!("{}/tree/{}", &REPO.link, &REPO.hash);
let link = Utf8Path::new(&REPO.link).join("tree").join(&REPO.hash);
let link = match path {
Some(path) => link.join(path),
None => link,
};
maud_move!(
footer .footer {
@ -98,7 +116,7 @@ pub fn footer() -> impl Renderable {
}
}
div .repo {
a href=(repo) {
a href=(link.as_str()) {
(&REPO.hash)
}
div {

View file

@ -73,5 +73,5 @@ pub fn home<'data, 'home, R>(main: R) -> impl Renderable + 'home
}
);
page("Home", main)
page("Home", main, None)
}

View file

@ -45,7 +45,7 @@ pub fn list<'data, 'list>(
}
);
page(title, list)
page(title, list, None)
}
fn section(year: i32, group: &[LinkDate]) -> impl Renderable + '_ {

View file

@ -1,3 +1,4 @@
use camino::Utf8Path;
use hypertext::{html_elements, maud_move, GlobalAttributes, Raw, Renderable};
use crate::html::base::{head, navbar, footer};
@ -19,10 +20,14 @@ pub fn bare<'data, 'html, R>(title: &'data str, main: R) -> impl Renderable + 'h
)
}
pub fn page<'data, 'main, 'page, T>(title: &'data str, main: T) -> impl Renderable + 'page
pub fn page<'data, 'main, 'html, T>(
title: &'data str,
main: T,
path: Option<&'data Utf8Path>,
) -> impl Renderable + 'html
where
'main : 'page,
'data : 'page,
'main : 'html,
'data : 'html,
T: Renderable + 'main
{
maud_move!(
@ -33,7 +38,7 @@ pub fn page<'data, 'main, 'page, T>(title: &'data str, main: T) -> impl Renderab
body {
(navbar())
(main)
(footer())
(footer(path))
}
}
)

View file

@ -1,21 +1,24 @@
use hypertext::{html_elements, maud_move, GlobalAttributes, Renderable};
use crate::gen::Sack;
use crate::html::misc::{show_bibliography, show_outline};
use crate::html::page;
use crate::md::Post;
use crate::text::md::Outline;
pub fn post<'fm, 'md, 'post, T>(
fm: &'fm Post,
pub fn post<'f, 'm, 's, 'html, T>(
fm: &'f Post,
content: T,
outline: Outline,
bib: Option<Vec<String>>,
) -> impl Renderable + 'post
sack: &'s Sack,
) -> impl Renderable + 'html
where
'fm: 'post,
'md: 'post,
T: Renderable + 'md
'f: 'html,
'm: 'html,
's: 'html,
T: Renderable + 'm
{
let main = maud_move!(
main .wiki-main {
@ -46,5 +49,5 @@ pub fn post<'fm, 'md, 'post, T>(
}
);
page(&fm.title, main)
page(&fm.title, main, sack.get_file())
}

View file

@ -12,7 +12,7 @@ pub fn map() -> impl Renderable {
(Raw("import 'photos';"))
}
}
))
), None)
}
pub fn search() -> impl Renderable {
@ -20,5 +20,5 @@ pub fn search() -> impl Renderable {
main {
}
))
), None)
}

View file

@ -53,5 +53,5 @@ pub fn wiki<'data, 'html, 'sack, T>(
}
);
page(&fm.title, main)
page(&fm.title, main, sack.get_file())
}

View file

@ -1,22 +1,42 @@
use std::process::Command;
use std::collections::HashMap;
use std::fs;
use std::process::Command;
use camino::{Utf8Path, Utf8PathBuf};
use chrono::Datelike;
use gen::{Asset, Sack, Content};
use clap::{Parser, ValueEnum};
use gen::{Asset, AssetKind, Content, FileItemKind, Output, PipelineItem, Sack};
use hayagriva::Library;
use html::{Link, LinkDate, Linkable};
use hypertext::{Raw, Renderable};
use once_cell::sync::Lazy;
use serde::Deserialize;
use text::md::Outline;
use crate::gen::Dynamic;
use crate::build::build_styles;
mod md;
mod html;
mod ts;
mod gen;
mod utils;
mod text;
mod watch;
mod build;
#[derive(Parser, Debug, Clone)]
struct Args {
#[clap(value_enum, index = 1, default_value = "build")]
mode: Mode,
}
#[derive(ValueEnum, Debug, Clone, Copy)]
enum Mode {
Build,
Watch,
}
#[derive(Debug)]
@ -54,7 +74,7 @@ impl Content for md::Post {
&'f self,
content: T,
outline: Outline,
_: &'s Sack,
sack: &'s Sack,
bib: Option<Vec<String>>,
) -> impl Renderable + 'html
where
@ -62,7 +82,7 @@ impl Content for md::Post {
'm: 'html,
's: 'html,
T: Renderable + 'm {
html::post(self, content, outline, bib)
html::post(self, content, outline, bib, sack)
}
fn as_link(&self, path: Utf8PathBuf) -> Option<Linkable> {
@ -171,19 +191,24 @@ fn to_list(list: Vec<LinkDate>) -> String {
html::list("", &groups).render().into()
}
fn transform<T>(meta: gen::Source) -> Asset
fn to_index<T>(item: PipelineItem) -> PipelineItem
where
T: for<'de> serde::Deserialize<'de>,
T: Content + 'static,
T: for<'de> Deserialize<'de> + Content + 'static,
{
let dir = meta.dirs.strip_prefix("content").unwrap();
let meta = match item {
PipelineItem::Skip(meta) if matches!(meta.kind, FileItemKind::Index) => meta,
_ => return item,
};
match meta.kind {
gen::SourceKind::Index => match meta.ext.as_str() {
"md" | "mdx" | "lhs" => {
let dir = meta.path.parent().unwrap().strip_prefix("content").unwrap();
let dir = match meta.path.file_stem().unwrap() {
"index" => dir.to_owned(),
name => dir.join(name),
};
let path = dir.join("index.html");
match meta.path.extension() {
Some("md" | "mdx" | "lhs") => {
let data = fs::read_to_string(&meta.path).unwrap();
let (fm, md) = md::preflight::<T>(&data);
let link = T::as_link(&fm, Utf8Path::new("/").join(dir));
@ -194,52 +219,59 @@ fn transform<T>(meta: gen::Source) -> Asset
T::transform(&fm, Raw(html), outline, sack, bib).render().into()
};
gen::Asset {
Output {
kind: Asset {
kind: gen::AssetKind::Html(Box::new(call)),
out: path,
meta,
}.into(),
path,
link,
meta,
}.into()
},
_ => meta.into(),
}
},
_ => gen::Asset {
kind: gen::AssetKind::Unknown,
out: dir.join(meta.path.file_name().unwrap()).to_owned(),
link: None,
meta,
}
},
gen::SourceKind::Asset => {
let loc = dir.join(meta.path.file_name().unwrap()).to_owned();
match meta.ext.as_str() {
"jpg" | "png" | "gif" => gen::Asset {
kind: gen::AssetKind::Image,
out: loc,
link: None,
fn to_bundle(item: PipelineItem) -> PipelineItem {
let meta = match item {
PipelineItem::Skip(meta) if matches!(meta.kind, FileItemKind::Bundle) => meta,
_ => return item,
};
let path = meta.path.strip_prefix("content").unwrap().to_owned();
match meta.path.extension() {
// any image
Some("jpg" | "png" | "gif") => {
Output {
kind: Asset {
kind: AssetKind::Image,
meta,
}.into(),
path,
link: None,
}.into()
},
"bib" => {
// bibliography
Some("bib") => {
let data = fs::read_to_string(&meta.path).unwrap();
let data = hayagriva::io::from_biblatex_str(&data).unwrap();
gen::Asset {
kind: gen::AssetKind::Bib(data),
out: loc,
link: None,
Output {
kind: Asset {
kind: AssetKind::Bibtex(data),
meta,
}
},
_ => gen::Asset {
kind: gen::AssetKind::Unknown,
out: loc,
}.into(),
path,
link: None,
meta,
}.into()
},
}
}
_ => meta.into(),
}
}
fn main() {
fn build() {
if fs::metadata("dist").is_ok() {
println!("Cleaning dist");
fs::remove_dir_all("dist").unwrap();
@ -247,69 +279,85 @@ fn main() {
fs::create_dir("dist").unwrap();
let assets: Vec<Vec<gen::Item>> = vec![
let assets: Vec<Output> = [
gen::gather("content/about.md", &["md"].into())
.into_iter()
.map(to_index::<md::Post> as fn(PipelineItem) -> PipelineItem),
gen::gather("content/posts/**/*", &["md", "mdx"].into())
.into_iter()
.map(to_index::<md::Post>),
gen::gather("content/slides/**/*", &["md", "lhs"].into())
.into_iter()
.map(to_index::<md::Slide>),
gen::gather("content/wiki/**/*", &["md"].into())
.into_iter()
.map(to_index::<md::Wiki>),
]
.into_iter()
.flatten()
.map(to_bundle)
.filter_map(|item| match item {
PipelineItem::Skip(skip) => {
println!("Skipping {}", skip.path);
None
},
PipelineItem::Take(take) => Some(take),
})
.collect();
let assets: Vec<Output> = vec![
assets,
vec![
gen::Virtual::new("map/index.html", |_| html::map().render().to_owned().into()).into(),
gen::Virtual::new("search/index.html", |_| html::search().render().to_owned().into()).into(),
gen::Asset {
Output {
kind: Dynamic::new(|_| html::map().render().to_owned().into()).into(),
path: "map/index.html".into(),
link: None,
},
Output {
kind: Dynamic::new(|_| html::search().render().to_owned().into()).into(),
path: "search/index.html".into(),
link: None,
},
Output {
kind: Asset {
kind: gen::AssetKind::Html(Box::new(|_| {
let data = std::fs::read_to_string("content/index.md").unwrap();
let (_, html, bib) = text::md::parse(&data, None);
let (_, html, _) = text::md::parse(&data, None);
html::home(Raw(html)).render().to_owned().into()
})),
out: "index.html".into(),
link: None,
meta: gen::Source {
kind: gen::SourceKind::Index,
ext: "md".into(),
dirs: "".into(),
})).into(),
meta: gen::FileItem {
kind: gen::FileItemKind::Index,
path: "content/index.md".into()
}
}.into(),
gen::Virtual("posts/index.html".into(), Box::new(|all|
to_list(all.get_links("posts/**/*.html"))
)).into(),
gen::Virtual("slides/index.html".into(), Box::new(|all|
to_list(all.get_links("slides/**/*.html"))
)).into(),
path: "index.html".into(),
link: None,
}.into(),
Output {
kind: Dynamic::new(|sack| to_list(sack.get_links("posts/**/*.html"))).into(),
path: "posts/index.html".into(),
link: None,
},
Output {
kind: Dynamic::new(|sack| to_list(sack.get_links("slides/**/*.html"))).into(),
path: "slides/index.html".into(),
link: None,
},
],
gen::gather("content/about.md", &["md"].into())
.into_iter()
.map(transform::<md::Post>)
.map(Into::into)
.collect(),
gen::gather("content/posts/**/*", &["md", "mdx"].into())
.into_iter()
.map(transform::<md::Post>)
.map(Into::into)
.collect(),
gen::gather("content/slides/**/*", &["md", "lhs"].into())
.into_iter()
.map(transform::<md::Slide>)
.map(Into::into)
.collect(),
gen::gather("content/wiki/**/*", &["md"].into())
.into_iter()
.map(transform::<md::Wiki>)
.map(Into::into)
.collect(),
];
let all: Vec<gen::Item> = assets
]
.into_iter()
.flatten()
.collect();
{
let now = std::time::Instant::now();
gen::render(&all);
gen::render_all(&assets);
println!("Elapsed: {:.2?}", now.elapsed());
}
utils::copy_recursively(std::path::Path::new("public"), std::path::Path::new("dist")).unwrap();
let css = grass::from_path("styles/styles.scss", &grass::Options::default()).unwrap();
fs::write("dist/styles.css", css).unwrap();
build_styles();
let res = Command::new("pagefind")
.args(["--site", "dist"])
@ -330,4 +378,17 @@ fn main() {
.unwrap();
println!("{}", String::from_utf8(res.stderr).unwrap());
}
fn main() {
let args = Args::parse();
match args.mode {
Mode::Build => build(),
Mode::Watch => {
build();
watch::watch().unwrap()
},
}
}

View file

@ -88,6 +88,9 @@ fn make_bib<'a, 'b>(stream: Vec<Event<'a>>, lib: &'b Library) -> (Vec<Event<'a>>
}
}
// add fake citation to make all entries show up
driver.citation(CitationRequest::from_items(lib.iter().map(CitationItem::with_entry).collect(), &STYLE, &LOCALE));
let res = driver.finish(BibliographyRequest { style: &STYLE, locale: None, locale_files: &LOCALE });
let mut n = 0;

View file

@ -1,6 +1,5 @@
use std::collections::HashMap;
use once_cell::sync::Lazy;
use tree_sitter::Language;
use tree_sitter_highlight::HighlightConfiguration;
use super::captures;
@ -17,6 +16,34 @@ macro_rules! query {
};
}
macro_rules! insert {
($_:tt $e:expr) => { $e };
}
macro_rules! merge {
([$($e:expr),+ $(,)?]) => { &format!(concat!($(insert!($e "{} ")),*), $($e),* ) };
($e:expr) => { $e };
}
macro_rules! language {
($name:expr, $lang:expr, $highlights:expr, $injections:expr, $locals:expr $(,)?) => {
(
$name,
{
let mut config = HighlightConfiguration::new(
$lang,
$name,
$highlights,
$injections,
$locals,
).unwrap();
config.configure(captures::NAMES);
config
}
)
};
}
pub static EXTENSIONS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
HashMap::from([
("hs", "haskell"),
@ -24,25 +51,12 @@ pub static EXTENSIONS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(||
("md", "markdown"),
("mdx", "markdown"),
("py", "python"),
("query", "query"),
// ("scm", "scheme"),
("scss", "scss"),
("scm", "scheme"),
("ts", "javascript"),
("typescript", "javascript")
])
});
fn config_for(
lang: Language,
name: &str,
highlights: &str,
injections: &str,
locals: &str,
) -> HighlightConfiguration {
let mut config = HighlightConfiguration::new(lang, name, highlights, injections, locals).unwrap();
config.configure(captures::NAMES);
config
}
pub static CONFIGS: Lazy<HashMap<&'static str, HighlightConfiguration>> = Lazy::new(|| {
HashMap::from([
@ -55,161 +69,129 @@ pub static CONFIGS: Lazy<HashMap<&'static str, HighlightConfiguration>> = Lazy::
// "",
// )
// ),
// (
// "css",
// config_for(
// tree_sitter_css::language(),
// query!("css/highlights"),
// "",
// "",
// )
// ),
(
"haskell",
config_for(
npezza93_tree_sitter_haskell::language(),
"haskell",
npezza93_tree_sitter_haskell::HIGHLIGHTS_QUERY,
language!(
"css",
tree_sitter_css::language(),
tree_sitter_css::HIGHLIGHTS_QUERY,
"",
"",
npezza93_tree_sitter_haskell::LOCALS_QUERY,
)
),
// (
// "html",
// config_for(
// tree_sitter_html::language(),
// tree_sitter_html::HIGHLIGHTS_QUERY,
// tree_sitter_html::INJECTIONS_QUERY,
// "",
// )
// ),
(
language!(
"haskell",
tree_sitter_haskell::language(),
tree_sitter_haskell::HIGHLIGHTS_QUERY,
"",
tree_sitter_haskell::LOCALS_QUERY,
),
language!(
"html",
tree_sitter_html::language(),
tree_sitter_html::HIGHLIGHTS_QUERY,
tree_sitter_html::INJECTIONS_QUERY,
"",
),
language!(
"javascript",
config_for(
tree_sitter_javascript::language(),
"javascript",
&format!("{} {}",
merge!([
query!("ecma/highlights"),
tree_sitter_javascript::HIGHLIGHT_QUERY,
),
tree_sitter_javascript::INJECTION_QUERY,
]),
tree_sitter_javascript::INJECTIONS_QUERY,
tree_sitter_javascript::LOCALS_QUERY,
)
),
(
language!(
"jsx",
config_for(
tree_sitter_javascript::language(),
"jsx",
&format!("{} {} {}",
merge!([
query!("ecma/highlights"),
tree_sitter_javascript::HIGHLIGHT_QUERY,
tree_sitter_javascript::JSX_HIGHLIGHT_QUERY,
),
tree_sitter_javascript::INJECTION_QUERY,
]),
tree_sitter_javascript::INJECTIONS_QUERY,
tree_sitter_javascript::LOCALS_QUERY,
)
),
(
language!(
"markdown",
config_for(
tree_sitter_md::language(),
"markdown",
tree_sitter_md::HIGHLIGHT_QUERY_BLOCK,
tree_sitter_md::INJECTION_QUERY_BLOCK,
"",
)
),
(
language!(
"python",
config_for(
tree_sitter_python::language(),
"python",
tree_sitter_python::HIGHLIGHTS_QUERY,
"",
"",
)
),
(
"query",
config_for(
tree_sitter_query::language(),
"query",
tree_sitter_query::HIGHLIGHTS_QUERY,
tree_sitter_query::INJECTIONS_QUERY,
language!(
"regex",
tree_sitter_regex::language(),
query!("regex/highlights"),
"",
"",
)
),
// (
// "regex",
// config_for(
// tree_sitter_regex::language(),
// query!("regex/highlights"),
// "",
// "",
// )
// ),
(
language!(
"rust",
config_for(
tree_sitter_rust::language(),
"rust",
tree_sitter_rust::HIGHLIGHTS_QUERY,
tree_sitter_rust::INJECTIONS_QUERY,
"",
)
),
// (
// "scheme",
// config_for(
// tree_sitter_scheme::language(),
// tree_sitter_scheme::HIGHLIGHTS_QUERY,
// "",
// "",
// )
// ),
// (
// "toml",
// config_for(
// tree_sitter_toml::language(),
// tree_sitter_toml::HIGHLIGHT_QUERY,
// "",
// "",
// )
// ),
// (
// "tsx",
// config_for(
// tree_sitter_typescript::language_tsx(),
// &format!("{} {} {} {}",
// query!("ecma/highlights"),
// tree_sitter_javascript::HIGHLIGHT_QUERY,
// tree_sitter_javascript::JSX_HIGHLIGHT_QUERY,
// tree_sitter_typescript::HIGHLIGHT_QUERY,
// ),
// tree_sitter_javascript::INJECTION_QUERY,
// &format!("{} {}",
// tree_sitter_javascript::LOCALS_QUERY,
// tree_sitter_typescript::LOCALS_QUERY
// )
// )
// ),
// (
// "typescript",
// config_for(
// tree_sitter_typescript::language_typescript(),
// &format!("{} {} {}",
// query!("ecma/highlights"),
// tree_sitter_javascript::HIGHLIGHT_QUERY,
// tree_sitter_typescript::HIGHLIGHT_QUERY,
// ),
// tree_sitter_javascript::INJECTION_QUERY,
// &format!("{} {}",
// tree_sitter_javascript::LOCALS_QUERY,
// tree_sitter_typescript::LOCALS_QUERY
// ),
// )
// ),
language!(
"scss",
tree_sitter_scss::language(),
merge!([
tree_sitter_css::HIGHLIGHTS_QUERY,
tree_sitter_scss::HIGHLIGHTS_QUERY,
]),
"",
"",
),
language!(
"query",
tree_sitter_query::language(),
tree_sitter_query::HIGHLIGHTS_QUERY,
"",
"",
),
language!(
"toml",
tree_sitter_toml_ng::language(),
tree_sitter_toml_ng::HIGHLIGHTS_QUERY,
"",
"",
),
language!(
"typescript",
tree_sitter_typescript::language_typescript(),
merge!([
query!("ecma/highlights"),
tree_sitter_javascript::HIGHLIGHT_QUERY,
tree_sitter_typescript::HIGHLIGHTS_QUERY,
]),
tree_sitter_javascript::INJECTIONS_QUERY,
merge!([
tree_sitter_javascript::LOCALS_QUERY,
tree_sitter_typescript::LOCALS_QUERY,
])
),
language!(
"tsx",
tree_sitter_typescript::language_tsx(),
merge!([
query!("ecma/highlights"),
tree_sitter_javascript::HIGHLIGHT_QUERY,
tree_sitter_javascript::JSX_HIGHLIGHT_QUERY,
tree_sitter_typescript::HIGHLIGHTS_QUERY,
]),
tree_sitter_javascript::INJECTIONS_QUERY,
merge!([
tree_sitter_javascript::LOCALS_QUERY,
tree_sitter_typescript::LOCALS_QUERY,
]),
),
])
});

94
src/watch.rs Normal file
View file

@ -0,0 +1,94 @@
use std::io::Result;
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
use std::time::Duration;
use notify::RecursiveMode;
use notify_debouncer_mini::new_debouncer;
use tungstenite::WebSocket;
use crate::build::build_styles;
fn new_thread_ws_incoming(
server: TcpListener,
client: Arc<Mutex<Vec<WebSocket<TcpStream>>>>,
) -> JoinHandle<()> {
std::thread::spawn(move || {
for stream in server.incoming() {
let socket = tungstenite::accept(stream.unwrap()).unwrap();
client.lock().unwrap().push(socket);
}
})
}
fn new_thread_ws_reload(
client: Arc<Mutex<Vec<WebSocket<TcpStream>>>>,
) -> (Sender<()>, JoinHandle<()>) {
let (tx, rx) = std::sync::mpsc::channel();
let thread = std::thread::spawn(move || {
while rx.recv().is_ok() {
let mut clients = client.lock().unwrap();
let mut broken = vec![];
for (i, socket) in clients.iter_mut().enumerate() {
match socket.send("reload".into()) {
Ok(_) => {}
Err(tungstenite::error::Error::Io(e)) => {
if e.kind() == std::io::ErrorKind::BrokenPipe {
broken.push(i);
}
}
Err(e) => {
eprintln!("Error: {:?}", e);
}
}
}
for i in broken.into_iter().rev() {
clients.remove(i);
}
// Close all but the last 10 connections
let len = clients.len();
if len > 10 {
for mut socket in clients.drain(0..len - 10) {
socket.close(None).ok();
}
}
}
});
(tx, thread)
}
pub fn watch() -> Result<()> {
let server = TcpListener::bind("127.0.0.1:1337")?;
let client = Arc::new(Mutex::new(vec![]));
let (tx, rx) = std::sync::mpsc::channel();
let mut debouncer = new_debouncer(Duration::from_secs(1), tx).unwrap();
debouncer
.watcher()
.watch(Path::new("./styles"), RecursiveMode::Recursive)
.unwrap();
let thread_i = new_thread_ws_incoming(server, client.clone());
let (tx_reload, thread_o) = new_thread_ws_reload(client.clone());
while let Ok(ev) = rx.recv().unwrap() {
build_styles();
tx_reload.send(()).unwrap();
}
thread_i.join().unwrap();
thread_o.join().unwrap();
Ok(())
}

View file

@ -1,28 +1,40 @@
.markdown {
> h1 {
font-size: 2.0274rem;
h1 {
font-size: 2.5rem;
}
> h2 {
font-size: 1.802rem;
h2 {
font-size: 1.8rem;
}
> h3 {
font-size: 1.602rem;
h3 {
font-size: 1.5rem;
}
> h4, > h5, > h6 {
font-size: 1.424rem;
h4, > h5, > h6 {
font-size: 1.2rem;
}
> p {
p {
margin: 0.5em 0;
line-height: 1.5em;
hyphens: auto;
text-align: justify;
line-height: 1.5em;
}
a:not([class]) {
ul, ol {
padding-left: 1em;
ul, ol {
padding-left: 1em;
}
}
li {
line-height: 1.5em;
}
a {
color: var(--c-primary);
font-family: var(--serif);
font-weight: 500;
@ -44,13 +56,6 @@
}
}
> ul, ol {
padding-left: 1em;
ul, ol {
padding-left: 1em;
}
}
img:not([class]) {
max-width: 100%;