⛏️ index : gitore.git

author Alexander von Gluck IV <alex@terarocket.io> 2025-12-15 15:05:35.0 -06:00:00
committer Alexander von Gluck IV <alex@terarocket.io> 2025-12-15 15:05:35.0 -06:00:00
commit
3737c5ea10662a0b5972e217d40449b85f01ddb5 [patch]
tree
96a49c8b7f322d5ed4d01554ef41818af6a23e9b
parent
23c300dd083d0b65d0c37faad38b654d82a03da8
download
3737c5ea10662a0b5972e217d40449b85f01ddb5.tar.gz

commit.body: Make links clickable in web interface



Diff

 Cargo.lock                 | 10 ++++++++++
 Cargo.toml                 |  1 +
 src/git.rs                 | 45 +++++++++++++++++++++++++++++++++++++++++++++
 src/main.rs                |  3 +++
 templates/repo/commit.html |  2 +-
 5 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 48edc78..3ad819c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -777,6 +777,7 @@
 "httparse",
 "humantime",
 "itertools 0.12.1",
 "linkify",
 "md5",
 "memchr",
 "moka",
@@ -1941,6 +1942,15 @@
 "cc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "linkify"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dfa36d52c581e9ec783a7ce2a5e0143da6237be5811a0b3153fedfdbe9f780"
dependencies = [
 "memchr",
]

[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 91c916a..b34830a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -50,6 +50,7 @@
httparse = "1.10"
humantime = "2.2"
itertools = "0.12.1"
linkify = "0.10.0"
md5 = "0.8"
memchr = "2.7"
moka = { version = "0.12.11", features = ["future"] }
diff --git a/src/git.rs b/src/git.rs
index d2ac9bd..e37026a 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -14,6 +14,7 @@
    traverse::tree::visit::Action,
};
use itertools::Either;
use linkify::{LinkFinder, LinkKind};
use moka::future::Cache;
use std::{
    borrow::Cow,
@@ -32,11 +33,50 @@
use tracing::{error, instrument, warn};
use yoke::{Yoke, Yokeable};


use crate::{
    methods::filters::DisplayHexBuffer,
    syntax_highlight::{ComrakHighlightAdapter, FileIdentifier, format_file, format_file_inner},
    unified_diff_builder::{Callback, UnifiedDiffBuilder},
};

/// Escape essential html

fn escape(text: &str, dest: &mut Vec<u8>) {
    for c in text.bytes() {
        match c {
            b'&' => dest.extend_from_slice(b"&amp;"),
            b'<' => dest.extend_from_slice(b"&lt;"),
            b'>' => dest.extend_from_slice(b"&gt;"),
            b'"' => dest.extend_from_slice(b"&quot;"),
            b'\'' => dest.extend_from_slice(b"&#39;"),
            _ => dest.push(c),
        }
    }
}

/// Find links in a BStr, make them clickable

pub fn linkify(text: &BStr) -> BString {
    let mut link_finder = LinkFinder::new();
    link_finder.url_must_have_scheme(true);

    let mut bytes = Vec::new();
    for span in link_finder.spans(&text.to_string()) {
        match span.kind() {
            Some(LinkKind::Url) => {
                let url = span.as_str().to_string();
                bytes.extend_from_slice(b"<a href=\"");
                escape(&url, &mut bytes);
                bytes.extend_from_slice(b"\" target=\"_blank\">");
                escape(span.as_str(), &mut bytes);
                bytes.extend_from_slice(b"</a>");
            },
            _ => {
                escape(span.as_str(), &mut bytes);
            }
        }
    }
    bytes.into()
}

type ReadmeCacheKey = (PathBuf, Option<Arc<str>>);

@@ -700,7 +740,6 @@
impl<'a> CommitInner<'a> {
    pub fn new(commit: gix::worktree::object::CommitRef<'a>, oid: [u8; 20]) -> Result<Self> {
        let message = commit.message();

        Ok(CommitInner {
            author: CommitUser::try_from(commit.author)?,
            committer: CommitUser::try_from(commit.committer)?,
@@ -752,6 +791,10 @@

    pub fn body(&self) -> &BStr {
        self.body
    }

    pub fn body_html_links(&self) -> BString {
        linkify(self.body)
    }
}

diff --git a/src/main.rs b/src/main.rs
index 2bfbdd4..490aceb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -92,6 +92,9 @@
    /// Configures the request timeout.

    #[clap(long, env="REQUEST_TIMEOUT", default_value_t = Duration::from_secs(10).into())]
    request_timeout: humantime::Duration,
    /// Configure an optional bug tracker prefix URL to link ticket numbers to (#XYZ)

    #[clap(long, env="BUG_TRACKER_PREFIX")]
    bug_tracker_prefix: Option<String>,
}

#[derive(Debug, Clone, Copy)]
diff --git a/templates/repo/commit.html b/templates/repo/commit.html
index 820dc61..535f1ed 100644
--- a/templates/repo/commit.html
+++ b/templates/repo/commit.html
@@ -45,7 +45,7 @@
</div>

<h2>{{ commit.get().summary() }}</h2>
<pre>{{ commit.get().body() }}</pre>
<pre>{{ commit.get().body_html_links()|escape("none") }}</pre>

<h3>Diff</h3>
<pre class="diff">{{ commit.diff_stats|safe }}