gitscope
← rgit / Diff · 2a9edba → 2a9edba
Changes 2a9edba..2a9edba
Patch commit
diff --git a/Cargo.lock b/Cargo.lock
index 1303f79..c750fb4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,30 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_colours"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32678233b67f9056b0c144b39d46dc3218637e8d84ad6038ded339e08b19620d"
+dependencies = [
+ "rgb",
+]
+
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -175,12 +199,64 @@ dependencies = [
"mime",
]
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bat"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd1212d80800b3d7614b3725e0b2ee3b45b2b7484805d54b5660c8fa6f706305"
+dependencies = [
+ "ansi_colours",
+ "ansi_term",
+ "bincode",
+ "bytesize",
+ "clircle",
+ "console",
+ "content_inspector",
+ "encoding",
+ "flate2",
+ "globset",
+ "once_cell",
+ "path_abs",
+ "regex",
+ "semver",
+ "serde",
+ "serde_yaml",
+ "syntect",
+ "thiserror",
+ "unicode-width",
+ "walkdir",
+]
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "bumpalo"
version = "3.10.0"
@@ -193,12 +269,24 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
+[[package]]
+name = "bytemuck"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c53dfa917ec274df8ed3c572698f381a24eef2efba9492d797301b72b6db408a"
+
[[package]]
name = "bytes"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+[[package]]
+name = "bytesize"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70"
+
[[package]]
name = "cache-padded"
version = "1.2.0"
@@ -295,6 +383,18 @@ dependencies = [
"os_str_bytes",
]
+[[package]]
+name = "clircle"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e68bbd985a63de680ab4d1ad77b6306611a8f961b282c8b5ab513e6de934e396"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "serde",
+ "winapi",
+]
+
[[package]]
name = "cloudabi"
version = "0.0.3"
@@ -313,6 +413,39 @@ dependencies = [
"cache-padded",
]
+[[package]]
+name = "console"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "once_cell",
+ "regex",
+ "terminal_size",
+ "unicode-width",
+ "winapi",
+]
+
+[[package]]
+name = "content_inspector"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
[[package]]
name = "crossbeam-channel"
version = "0.5.5"
@@ -359,6 +492,76 @@ dependencies = [
"once_cell",
]
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
+name = "encoding"
+version = "0.2.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
+dependencies = [
+ "encoding-index-japanese",
+ "encoding-index-korean",
+ "encoding-index-simpchinese",
+ "encoding-index-singlebyte",
+ "encoding-index-tradchinese",
+]
+
+[[package]]
+name = "encoding-index-japanese"
+version = "1.20141219.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
+dependencies = [
+ "encoding_index_tests",
+]
+
+[[package]]
+name = "encoding-index-korean"
+version = "1.20141219.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
+dependencies = [
+ "encoding_index_tests",
+]
+
+[[package]]
+name = "encoding-index-simpchinese"
+version = "1.20141219.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
+dependencies = [
+ "encoding_index_tests",
+]
+
+[[package]]
+name = "encoding-index-singlebyte"
+version = "1.20141219.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
+dependencies = [
+ "encoding_index_tests",
+]
+
+[[package]]
+name = "encoding-index-tradchinese"
+version = "1.20141219.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
+dependencies = [
+ "encoding_index_tests",
+]
+
+[[package]]
+name = "encoding_index_tests"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
+
[[package]]
name = "error-chain"
version = "0.12.4"
@@ -383,6 +586,16 @@ dependencies = [
"instant",
]
+[[package]]
+name = "flate2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
[[package]]
name = "fnv"
version = "1.0.7"
@@ -541,6 +754,19 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+[[package]]
+name = "globset"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "fnv",
+ "log",
+ "regex",
+]
+
[[package]]
name = "hashbrown"
version = "0.12.1"
@@ -753,6 +979,21 @@ dependencies = [
"vcpkg",
]
+[[package]]
+name = "line-wrap"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
+dependencies = [
+ "safemem",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
[[package]]
name = "lock_api"
version = "0.4.7"
@@ -842,6 +1083,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+[[package]]
+name = "miniz_oxide"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+dependencies = [
+ "adler",
+]
+
[[package]]
name = "mio"
version = "0.8.4"
@@ -933,6 +1183,28 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+[[package]]
+name = "onig"
+version = "6.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1eb3502504c9c8b06634b38bfdda86a9a8cef6277f3dec4d8b17c115110dd2a3"
+dependencies = [
+ "bitflags",
+ "lazy_static",
+ "libc",
+ "onig_sys",
+]
+
+[[package]]
+name = "onig_sys"
+version = "69.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bf3fbc9b931b6c9af85d219c7943c274a6ad26cff7488a2210215edd5f49bf8"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
[[package]]
name = "openssl-probe"
version = "0.1.5"
@@ -993,6 +1265,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd"
+[[package]]
+name = "path_abs"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3"
+dependencies = [
+ "std_prelude",
+]
+
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -1075,6 +1356,20 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
+[[package]]
+name = "plist"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225"
+dependencies = [
+ "base64",
+ "indexmap",
+ "line-wrap",
+ "serde",
+ "time 0.3.11",
+ "xml-rs",
+]
+
[[package]]
name = "polling"
version = "2.2.0"
@@ -1266,6 +1561,23 @@ dependencies = [
"bitflags",
]
+[[package]]
+name = "regex"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+
[[package]]
name = "remove_dir_all"
version = "0.5.3"
@@ -1275,6 +1587,15 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "rgb"
+version = "0.8.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3b221de559e4a29df3b957eec92bc0de6bc8eaf6ca9cfed43e5e1d67ff65a34"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "rgit"
version = "0.1.0"
@@ -1282,6 +1603,7 @@ dependencies = [
"arc-swap",
"askama",
"axum",
+ "bat",
"clap",
"futures",
"git2",
@@ -1291,6 +1613,7 @@ dependencies = [
"moka",
"path-clean",
"serde",
+ "syntect",
"time 0.3.11",
"timeago",
"tokio",
@@ -1308,6 +1631,12 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -1384,6 +1713,18 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_yaml"
+version = "0.8.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
+dependencies = [
+ "indexmap",
+ "ryu",
+ "serde",
+ "yaml-rust",
+]
+
[[package]]
name = "sharded-slab"
version = "0.1.4"
@@ -1445,6 +1786,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "std_prelude"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe"
+
[[package]]
name = "strsim"
version = "0.10.0"
@@ -1468,6 +1815,29 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
+[[package]]
+name = "syntect"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8"
+dependencies = [
+ "bincode",
+ "bitflags",
+ "flate2",
+ "fnv",
+ "lazy_static",
+ "once_cell",
+ "onig",
+ "plist",
+ "regex-syntax",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "thiserror",
+ "walkdir",
+ "yaml-rust",
+]
+
[[package]]
name = "tagptr"
version = "0.2.0"
@@ -1497,6 +1867,16 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "terminal_size"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "textwrap"
version = "0.15.0"
@@ -1548,6 +1928,7 @@ version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
dependencies = [
+ "itoa",
"libc",
"num_threads",
]
@@ -1765,6 +2146,12 @@ dependencies = [
"tinyvec",
]
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
[[package]]
name = "url"
version = "2.2.2"
@@ -1989,3 +2376,18 @@ name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/Cargo.toml b/Cargo.toml
index acd49b9..2577af8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2021"
askama = "0.11"
arc-swap = "1.5"
axum = "0.5"
+bat = { version = "0.21", default-features = false, features = ["build-assets"] }
clap = { version = "3.2", features = ["cargo"] }
futures = "0.3"
git2 = "0.14"
@@ -18,6 +19,7 @@ md5 = "0.7"
moka = { version = "0.9", features = ["future"] }
path-clean = "0.1"
serde = { version = "1.0", features = ["derive"] }
+syntect = "5"
time = "0.3"
timeago = "0.3"
tokio = { version = "1.19", features = ["full"] }
diff --git a/src/git.rs b/src/git.rs
index 74fcf82..27a6315 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -7,8 +7,12 @@ use std::{
};
use arc_swap::ArcSwapOption;
-use git2::{ObjectType, Oid, Repository, Signature};
+use git2::{
+ DiffFormat, DiffLineType, DiffOptions, DiffStatsFormat, ObjectType, Oid, Repository, Signature,
+};
use moka::future::Cache;
+use syntect::html::{ClassStyle, ClassedHTMLGenerator};
+use syntect::parsing::SyntaxSet;
use time::OffsetDateTime;
pub type RepositoryMetadataList = BTreeMap<Option<String>, Vec<RepositoryMetadata>>;
@@ -42,7 +46,12 @@ impl Default for Git {
}
impl Git {
- pub async fn get_commit<'a>(&'a self, repo: PathBuf, commit: &str) -> Arc<Commit> {
+ pub async fn get_commit<'a>(
+ &'a self,
+ repo: PathBuf,
+ commit: &str,
+ syntax_set: Arc<SyntaxSet>,
+ ) -> Arc<Commit> {
let commit = Oid::from_str(commit).unwrap();
self.commits
@@ -50,8 +59,14 @@ impl Git {
tokio::task::spawn_blocking(move || {
let repo = Repository::open_bare(repo).unwrap();
let commit = repo.find_commit(commit).unwrap();
+ let (diff_output, diff_stats) =
+ fetch_diff_and_stats(&repo, &commit, &syntax_set);
+
+ let mut commit = Commit::from(commit);
+ commit.diff_stats = diff_stats;
+ commit.diff = diff_output;
- Arc::new(Commit::from(commit))
+ Arc::new(commit)
})
.await
.unwrap()
@@ -153,13 +168,17 @@ impl Git {
.await
}
- pub async fn get_latest_commit(&self, repo: PathBuf) -> Commit {
+ pub async fn get_latest_commit(&self, repo: PathBuf, syntax_set: Arc<SyntaxSet>) -> Commit {
tokio::task::spawn_blocking(move || {
let repo = Repository::open_bare(repo).unwrap();
let head = repo.head().unwrap();
let commit = head.peel_to_commit().unwrap();
+ let (diff_output, diff_stats) = fetch_diff_and_stats(&repo, &commit, &syntax_set);
- Commit::from(commit)
+ let mut commit = Commit::from(commit);
+ commit.diff_stats = diff_stats;
+ commit.diff = diff_output;
+ commit
})
.await
.unwrap()
@@ -316,6 +335,8 @@ pub struct Commit {
parents: Vec<String>,
summary: String,
body: String,
+ pub diff_stats: String,
+ pub diff: String,
}
impl From<git2::Commit<'_>> for Commit {
@@ -328,6 +349,8 @@ impl From<git2::Commit<'_>> for Commit {
parents: commit.parent_ids().map(|v| v.to_string()).collect(),
summary: commit.summary().unwrap().to_string(),
body: commit.body().map(ToString::to_string).unwrap_or_default(),
+ diff_stats: String::with_capacity(0),
+ diff: String::with_capacity(0),
}
}
}
@@ -362,6 +385,83 @@ impl Commit {
}
}
+fn fetch_diff_and_stats(
+ repo: &git2::Repository,
+ commit: &git2::Commit<'_>,
+ syntax_set: &SyntaxSet,
+) -> (String, String) {
+ let current_tree = commit.tree().unwrap();
+ let parent_tree = commit.parents().next().and_then(|v| v.tree().ok());
+ let mut diff_opts = DiffOptions::new();
+ let diff = repo
+ .diff_tree_to_tree(
+ parent_tree.as_ref(),
+ Some(&current_tree),
+ Some(&mut diff_opts),
+ )
+ .unwrap();
+ let diff_stats = diff
+ .stats()
+ .unwrap()
+ .to_buf(DiffStatsFormat::FULL, 80)
+ .unwrap()
+ .as_str()
+ .unwrap()
+ .to_string();
+ let diff_output = format_diff(&diff, &syntax_set);
+
+ (diff_output, diff_stats)
+}
+
+fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> String {
+ let mut diff_output = String::new();
+
+ diff.print(DiffFormat::Patch, |delta, _diff_hunk, diff_line| {
+ let (class, prefix, should_highlight_as_source) = match diff_line.origin_value() {
+ DiffLineType::Addition => (Some("add-line"), "+", true),
+ DiffLineType::Deletion => (Some("remove-line"), "-", true),
+ DiffLineType::Context => (None, " ", true),
+ DiffLineType::AddEOFNL => (Some("remove-line"), "", false),
+ DiffLineType::DeleteEOFNL => (Some("add-line"), "", false),
+ DiffLineType::FileHeader => (Some("file-header"), "", false),
+ _ => (None, "", false),
+ };
+
+ let line = std::str::from_utf8(diff_line.content()).unwrap();
+
+ let extension = if should_highlight_as_source {
+ let path = delta.new_file().path().unwrap();
+ path.extension()
+ .or(path.file_name())
+ .unwrap()
+ .to_string_lossy()
+ } else {
+ Cow::Borrowed("patch")
+ };
+ let syntax = syntax_set
+ .find_syntax_by_extension(&extension)
+ .unwrap_or(syntax_set.find_syntax_plain_text());
+ let mut html_generator =
+ ClassedHTMLGenerator::new_with_class_style(syntax, &syntax_set, ClassStyle::Spaced);
+ html_generator
+ .parse_html_for_line_which_includes_newline(line)
+ .unwrap();
+ if let Some(class) = class {
+ diff_output.push_str(&format!("<span class=\"diff-{class}\">"));
+ }
+ diff_output.push_str(prefix);
+ diff_output.push_str(&html_generator.finalize());
+ if class.is_some() {
+ diff_output.push_str("</span>");
+ }
+
+ true
+ })
+ .unwrap();
+
+ diff_output
+}
+
fn fetch_repository_metadata_impl(
start: &Path,
current: &Path,
diff --git a/src/main.rs b/src/main.rs
index 5fc349e..a6a4711 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,9 @@ use axum::{
body::Body, handler::Handler, http::HeaderValue, response::Response, routing::get, Extension,
Router,
};
+use bat::assets::HighlightingAssets;
+use std::sync::Arc;
+use syntect::html::ClassStyle;
use tower_layer::layer_fn;
use crate::{git::Git, layers::logger::LoggingMiddleware};
@@ -21,15 +24,27 @@ async fn main() {
let subscriber = subscriber.pretty();
subscriber.init();
+ let bat_assets = HighlightingAssets::from_binary();
+ let syntax_set = bat_assets.get_syntax_set().unwrap().clone();
+ let theme = bat_assets.get_theme("GitHub");
+ let css = Box::leak(
+ syntect::html::css_for_theme_with_class_style(theme, ClassStyle::Spaced)
+ .unwrap()
+ .into_boxed_str()
+ .into_boxed_bytes(),
+ );
+
let app = Router::new()
.route("/", get(methods::index::handle))
.route(
"/style.css",
get(static_css(include_bytes!("../statics/style.css"))),
)
+ .route("/highlight.css", get(static_css(css)))
.fallback(methods::repo::service.into_service())
.layer(layer_fn(LoggingMiddleware))
- .layer(Extension(Git::default()));
+ .layer(Extension(Git::default()))
+ .layer(Extension(Arc::new(syntax_set)));
axum::Server::bind(&"127.0.0.1:3333".parse().unwrap())
.serve(app.into_make_service_with_connect_info::<std::net::SocketAddr>())
diff --git a/src/methods/repo.rs b/src/methods/repo.rs
index a1d583c..a04fd75 100644
--- a/src/methods/repo.rs
+++ b/src/methods/repo.rs
@@ -14,6 +14,7 @@ use axum::{
};
use path_clean::PathClean;
use serde::Deserialize;
+use syntect::parsing::SyntaxSet;
use tower::{util::BoxCloneService, Service};
use super::filters;
@@ -205,6 +206,7 @@ pub async fn handle_commit(
Extension(repo): Extension<Repository>,
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Git>,
+ Extension(syntax_set): Extension<Arc<SyntaxSet>>,
Query(query): Query<CommitQuery>,
) -> Html<String> {
#[derive(Template)]
@@ -218,9 +220,9 @@ pub async fn handle_commit(
View {
repo,
commit: if let Some(commit) = query.id {
- git.get_commit(repository_path, &commit).await
+ git.get_commit(repository_path, &commit, syntax_set).await
} else {
- Arc::new(git.get_latest_commit(repository_path).await)
+ Arc::new(git.get_latest_commit(repository_path, syntax_set).await)
},
}
.render()
diff --git a/statics/style.css b/statics/style.css
index 51cae2b..4cf9841 100644
--- a/statics/style.css
+++ b/statics/style.css
@@ -91,3 +91,22 @@ pre.h2-first-line::first-line {
font-size: 1.5em;
font-weight: bold;
}
+
+
+.diff-file-header {
+ font-weight: bold;
+}
+
+.diff-file-header > span > span {
+ font-weight: normal;
+}
+
+.diff-add-line {
+ background: #e6ffec;
+ display: block;
+}
+
+.diff-remove-line {
+ background: #ffebe9;
+ display: block;
+}
diff --git a/templates/repo/commit.html b/templates/repo/commit.html
index 70eeee2..647a32e 100644
--- a/templates/repo/commit.html
+++ b/templates/repo/commit.html
@@ -1,5 +1,9 @@
{% extends "repo/base.html" %}
+{% block head %}
+<link rel="stylesheet" type="text/css" href="/highlight.css" />
+{% endblock %}
+
{% block commit_nav_class %}active{% endblock %}
{% block content %}
@@ -34,4 +38,8 @@
<h2>{{ commit.summary() }}</h2>
<pre>{{ commit.body() }}</pre>
+
+<h3>Diff</h3>
+<pre>{{ commit.diff_stats|safe }}
+{{ commit.diff|safe }}</pre>
{% endblock %}
\ No newline at end of file